Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* |
michael@0 | 2 | ******************************************************************************* |
michael@0 | 3 | * |
michael@0 | 4 | * Copyright (C) 2001-2012, International Business Machines |
michael@0 | 5 | * Corporation and others. All Rights Reserved. |
michael@0 | 6 | * |
michael@0 | 7 | ******************************************************************************* |
michael@0 | 8 | * file name: ucaelems.cpp |
michael@0 | 9 | * encoding: US-ASCII |
michael@0 | 10 | * tab size: 8 (not used) |
michael@0 | 11 | * indentation:4 |
michael@0 | 12 | * |
michael@0 | 13 | * created 02/22/2001 |
michael@0 | 14 | * created by: Vladimir Weinstein |
michael@0 | 15 | * |
michael@0 | 16 | * This program reads the Franctional UCA table and generates |
michael@0 | 17 | * internal format for UCA table as well as inverse UCA table. |
michael@0 | 18 | * It then writes binary files containing the data: ucadata.dat |
michael@0 | 19 | * & invuca.dat |
michael@0 | 20 | * |
michael@0 | 21 | * date name comments |
michael@0 | 22 | * 03/02/2001 synwee added setMaxExpansion |
michael@0 | 23 | * 03/07/2001 synwee merged UCA's maxexpansion and tailoring's |
michael@0 | 24 | */ |
michael@0 | 25 | |
michael@0 | 26 | #include "unicode/utypes.h" |
michael@0 | 27 | |
michael@0 | 28 | #if !UCONFIG_NO_COLLATION |
michael@0 | 29 | |
michael@0 | 30 | #include "unicode/uchar.h" |
michael@0 | 31 | #include "unicode/unistr.h" |
michael@0 | 32 | #include "unicode/ucoleitr.h" |
michael@0 | 33 | #include "unicode/normlzr.h" |
michael@0 | 34 | #include "unicode/utf16.h" |
michael@0 | 35 | #include "normalizer2impl.h" |
michael@0 | 36 | #include "ucol_elm.h" |
michael@0 | 37 | #include "ucol_tok.h" |
michael@0 | 38 | #include "ucol_cnt.h" |
michael@0 | 39 | #include "unicode/caniter.h" |
michael@0 | 40 | #include "cmemory.h" |
michael@0 | 41 | #include "uassert.h" |
michael@0 | 42 | |
michael@0 | 43 | U_NAMESPACE_USE |
michael@0 | 44 | |
michael@0 | 45 | static uint32_t uprv_uca_processContraction(CntTable *contractions, UCAElements *element, uint32_t existingCE, UErrorCode *status); |
michael@0 | 46 | |
michael@0 | 47 | U_CDECL_BEGIN |
michael@0 | 48 | static int32_t U_CALLCONV |
michael@0 | 49 | prefixLookupHash(const UHashTok e) { |
michael@0 | 50 | UCAElements *element = (UCAElements *)e.pointer; |
michael@0 | 51 | UChar buf[256]; |
michael@0 | 52 | UHashTok key; |
michael@0 | 53 | key.pointer = buf; |
michael@0 | 54 | uprv_memcpy(buf, element->cPoints, element->cSize*sizeof(UChar)); |
michael@0 | 55 | buf[element->cSize] = 0; |
michael@0 | 56 | //key.pointer = element->cPoints; |
michael@0 | 57 | //element->cPoints[element->cSize] = 0; |
michael@0 | 58 | return uhash_hashUChars(key); |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | static int8_t U_CALLCONV |
michael@0 | 62 | prefixLookupComp(const UHashTok e1, const UHashTok e2) { |
michael@0 | 63 | UCAElements *element1 = (UCAElements *)e1.pointer; |
michael@0 | 64 | UCAElements *element2 = (UCAElements *)e2.pointer; |
michael@0 | 65 | |
michael@0 | 66 | UChar buf1[256]; |
michael@0 | 67 | UHashTok key1; |
michael@0 | 68 | key1.pointer = buf1; |
michael@0 | 69 | uprv_memcpy(buf1, element1->cPoints, element1->cSize*sizeof(UChar)); |
michael@0 | 70 | buf1[element1->cSize] = 0; |
michael@0 | 71 | |
michael@0 | 72 | UChar buf2[256]; |
michael@0 | 73 | UHashTok key2; |
michael@0 | 74 | key2.pointer = buf2; |
michael@0 | 75 | uprv_memcpy(buf2, element2->cPoints, element2->cSize*sizeof(UChar)); |
michael@0 | 76 | buf2[element2->cSize] = 0; |
michael@0 | 77 | |
michael@0 | 78 | return uhash_compareUChars(key1, key2); |
michael@0 | 79 | } |
michael@0 | 80 | U_CDECL_END |
michael@0 | 81 | |
michael@0 | 82 | static int32_t uprv_uca_addExpansion(ExpansionTable *expansions, uint32_t value, UErrorCode *status) { |
michael@0 | 83 | if(U_FAILURE(*status)) { |
michael@0 | 84 | return 0; |
michael@0 | 85 | } |
michael@0 | 86 | if(expansions->CEs == NULL) { |
michael@0 | 87 | expansions->CEs = (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE*sizeof(uint32_t)); |
michael@0 | 88 | /* test for NULL */ |
michael@0 | 89 | if (expansions->CEs == NULL) { |
michael@0 | 90 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 91 | return 0; |
michael@0 | 92 | } |
michael@0 | 93 | expansions->size = INIT_EXP_TABLE_SIZE; |
michael@0 | 94 | expansions->position = 0; |
michael@0 | 95 | } |
michael@0 | 96 | |
michael@0 | 97 | if(expansions->position == expansions->size) { |
michael@0 | 98 | uint32_t *newData = (uint32_t *)uprv_realloc(expansions->CEs, 2*expansions->size*sizeof(uint32_t)); |
michael@0 | 99 | if(newData == NULL) { |
michael@0 | 100 | #ifdef UCOL_DEBUG |
michael@0 | 101 | fprintf(stderr, "out of memory for expansions\n"); |
michael@0 | 102 | #endif |
michael@0 | 103 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 104 | return -1; |
michael@0 | 105 | } |
michael@0 | 106 | expansions->CEs = newData; |
michael@0 | 107 | expansions->size *= 2; |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | expansions->CEs[expansions->position] = value; |
michael@0 | 111 | return(expansions->position++); |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | U_CAPI tempUCATable* U_EXPORT2 |
michael@0 | 115 | uprv_uca_initTempTable(UCATableHeader *image, UColOptionSet *opts, const UCollator *UCA, UColCETags initTag, UColCETags supplementaryInitTag, UErrorCode *status) { |
michael@0 | 116 | MaxJamoExpansionTable *maxjet; |
michael@0 | 117 | MaxExpansionTable *maxet; |
michael@0 | 118 | tempUCATable *t = (tempUCATable *)uprv_malloc(sizeof(tempUCATable)); |
michael@0 | 119 | /* test for NULL */ |
michael@0 | 120 | if (t == NULL) { |
michael@0 | 121 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 122 | return NULL; |
michael@0 | 123 | } |
michael@0 | 124 | uprv_memset(t, 0, sizeof(tempUCATable)); |
michael@0 | 125 | |
michael@0 | 126 | maxet = (MaxExpansionTable *)uprv_malloc(sizeof(MaxExpansionTable)); |
michael@0 | 127 | if (maxet == NULL) { |
michael@0 | 128 | goto allocation_failure; |
michael@0 | 129 | } |
michael@0 | 130 | uprv_memset(maxet, 0, sizeof(MaxExpansionTable)); |
michael@0 | 131 | t->maxExpansions = maxet; |
michael@0 | 132 | |
michael@0 | 133 | maxjet = (MaxJamoExpansionTable *)uprv_malloc(sizeof(MaxJamoExpansionTable)); |
michael@0 | 134 | if (maxjet == NULL) { |
michael@0 | 135 | goto allocation_failure; |
michael@0 | 136 | } |
michael@0 | 137 | uprv_memset(maxjet, 0, sizeof(MaxJamoExpansionTable)); |
michael@0 | 138 | t->maxJamoExpansions = maxjet; |
michael@0 | 139 | |
michael@0 | 140 | t->image = image; |
michael@0 | 141 | t->options = opts; |
michael@0 | 142 | |
michael@0 | 143 | t->UCA = UCA; |
michael@0 | 144 | t->expansions = (ExpansionTable *)uprv_malloc(sizeof(ExpansionTable)); |
michael@0 | 145 | /* test for NULL */ |
michael@0 | 146 | if (t->expansions == NULL) { |
michael@0 | 147 | goto allocation_failure; |
michael@0 | 148 | } |
michael@0 | 149 | uprv_memset(t->expansions, 0, sizeof(ExpansionTable)); |
michael@0 | 150 | |
michael@0 | 151 | t->mapping = utrie_open(NULL, NULL, UCOL_ELM_TRIE_CAPACITY, |
michael@0 | 152 | UCOL_SPECIAL_FLAG | (initTag<<24), |
michael@0 | 153 | UCOL_SPECIAL_FLAG | (supplementaryInitTag << 24), |
michael@0 | 154 | TRUE); // Do your own mallocs for the structure, array and have linear Latin 1 |
michael@0 | 155 | if (U_FAILURE(*status)) { |
michael@0 | 156 | goto allocation_failure; |
michael@0 | 157 | } |
michael@0 | 158 | t->prefixLookup = uhash_open(prefixLookupHash, prefixLookupComp, NULL, status); |
michael@0 | 159 | if (U_FAILURE(*status)) { |
michael@0 | 160 | goto allocation_failure; |
michael@0 | 161 | } |
michael@0 | 162 | uhash_setValueDeleter(t->prefixLookup, uprv_free); |
michael@0 | 163 | |
michael@0 | 164 | t->contractions = uprv_cnttab_open(t->mapping, status); |
michael@0 | 165 | if (U_FAILURE(*status)) { |
michael@0 | 166 | goto cleanup; |
michael@0 | 167 | } |
michael@0 | 168 | |
michael@0 | 169 | /* copy UCA's maxexpansion and merge as we go along */ |
michael@0 | 170 | if (UCA != NULL) { |
michael@0 | 171 | /* adding an extra initial value for easier manipulation */ |
michael@0 | 172 | maxet->size = (int32_t)(UCA->lastEndExpansionCE - UCA->endExpansionCE) + 2; |
michael@0 | 173 | maxet->position = maxet->size - 1; |
michael@0 | 174 | maxet->endExpansionCE = |
michael@0 | 175 | (uint32_t *)uprv_malloc(sizeof(uint32_t) * maxet->size); |
michael@0 | 176 | /* test for NULL */ |
michael@0 | 177 | if (maxet->endExpansionCE == NULL) { |
michael@0 | 178 | goto allocation_failure; |
michael@0 | 179 | } |
michael@0 | 180 | maxet->expansionCESize = |
michael@0 | 181 | (uint8_t *)uprv_malloc(sizeof(uint8_t) * maxet->size); |
michael@0 | 182 | /* test for NULL */ |
michael@0 | 183 | if (maxet->expansionCESize == NULL) { |
michael@0 | 184 | goto allocation_failure; |
michael@0 | 185 | } |
michael@0 | 186 | /* initialized value */ |
michael@0 | 187 | *(maxet->endExpansionCE) = 0; |
michael@0 | 188 | *(maxet->expansionCESize) = 0; |
michael@0 | 189 | uprv_memcpy(maxet->endExpansionCE + 1, UCA->endExpansionCE, |
michael@0 | 190 | sizeof(uint32_t) * (maxet->size - 1)); |
michael@0 | 191 | uprv_memcpy(maxet->expansionCESize + 1, UCA->expansionCESize, |
michael@0 | 192 | sizeof(uint8_t) * (maxet->size - 1)); |
michael@0 | 193 | } |
michael@0 | 194 | else { |
michael@0 | 195 | maxet->size = 0; |
michael@0 | 196 | } |
michael@0 | 197 | maxjet->endExpansionCE = NULL; |
michael@0 | 198 | maxjet->isV = NULL; |
michael@0 | 199 | maxjet->size = 0; |
michael@0 | 200 | maxjet->position = 0; |
michael@0 | 201 | maxjet->maxLSize = 1; |
michael@0 | 202 | maxjet->maxVSize = 1; |
michael@0 | 203 | maxjet->maxTSize = 1; |
michael@0 | 204 | |
michael@0 | 205 | t->unsafeCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 206 | /* test for NULL */ |
michael@0 | 207 | if (t->unsafeCP == NULL) { |
michael@0 | 208 | goto allocation_failure; |
michael@0 | 209 | } |
michael@0 | 210 | t->contrEndCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 211 | /* test for NULL */ |
michael@0 | 212 | if (t->contrEndCP == NULL) { |
michael@0 | 213 | goto allocation_failure; |
michael@0 | 214 | } |
michael@0 | 215 | uprv_memset(t->unsafeCP, 0, UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 216 | uprv_memset(t->contrEndCP, 0, UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 217 | t->cmLookup = NULL; |
michael@0 | 218 | return t; |
michael@0 | 219 | |
michael@0 | 220 | allocation_failure: |
michael@0 | 221 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 222 | cleanup: |
michael@0 | 223 | uprv_uca_closeTempTable(t); |
michael@0 | 224 | return NULL; |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | static tempUCATable* U_EXPORT2 |
michael@0 | 228 | uprv_uca_cloneTempTable(tempUCATable *t, UErrorCode *status) { |
michael@0 | 229 | if(U_FAILURE(*status)) { |
michael@0 | 230 | return NULL; |
michael@0 | 231 | } |
michael@0 | 232 | |
michael@0 | 233 | tempUCATable *r = (tempUCATable *)uprv_malloc(sizeof(tempUCATable)); |
michael@0 | 234 | /* test for NULL */ |
michael@0 | 235 | if (r == NULL) { |
michael@0 | 236 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 237 | return NULL; |
michael@0 | 238 | } |
michael@0 | 239 | uprv_memset(r, 0, sizeof(tempUCATable)); |
michael@0 | 240 | |
michael@0 | 241 | /* mapping */ |
michael@0 | 242 | if(t->mapping != NULL) { |
michael@0 | 243 | /*r->mapping = ucmpe32_clone(t->mapping, status);*/ |
michael@0 | 244 | r->mapping = utrie_clone(NULL, t->mapping, NULL, 0); |
michael@0 | 245 | } |
michael@0 | 246 | |
michael@0 | 247 | // a hashing clone function would be very nice. We have none currently... |
michael@0 | 248 | // However, we should be good, as closing should not produce any prefixed elements. |
michael@0 | 249 | r->prefixLookup = NULL; // prefixes are not used in closing |
michael@0 | 250 | |
michael@0 | 251 | /* expansions */ |
michael@0 | 252 | if(t->expansions != NULL) { |
michael@0 | 253 | r->expansions = (ExpansionTable *)uprv_malloc(sizeof(ExpansionTable)); |
michael@0 | 254 | /* test for NULL */ |
michael@0 | 255 | if (r->expansions == NULL) { |
michael@0 | 256 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 257 | goto cleanup; |
michael@0 | 258 | } |
michael@0 | 259 | r->expansions->position = t->expansions->position; |
michael@0 | 260 | r->expansions->size = t->expansions->size; |
michael@0 | 261 | if(t->expansions->CEs != NULL) { |
michael@0 | 262 | r->expansions->CEs = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->expansions->size); |
michael@0 | 263 | /* test for NULL */ |
michael@0 | 264 | if (r->expansions->CEs == NULL) { |
michael@0 | 265 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 266 | goto cleanup; |
michael@0 | 267 | } |
michael@0 | 268 | uprv_memcpy(r->expansions->CEs, t->expansions->CEs, sizeof(uint32_t)*t->expansions->position); |
michael@0 | 269 | } else { |
michael@0 | 270 | r->expansions->CEs = NULL; |
michael@0 | 271 | } |
michael@0 | 272 | } |
michael@0 | 273 | |
michael@0 | 274 | if(t->contractions != NULL) { |
michael@0 | 275 | r->contractions = uprv_cnttab_clone(t->contractions, status); |
michael@0 | 276 | // Check for cloning failure. |
michael@0 | 277 | if (r->contractions == NULL) { |
michael@0 | 278 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 279 | goto cleanup; |
michael@0 | 280 | } |
michael@0 | 281 | r->contractions->mapping = r->mapping; |
michael@0 | 282 | } |
michael@0 | 283 | |
michael@0 | 284 | if(t->maxExpansions != NULL) { |
michael@0 | 285 | r->maxExpansions = (MaxExpansionTable *)uprv_malloc(sizeof(MaxExpansionTable)); |
michael@0 | 286 | /* test for NULL */ |
michael@0 | 287 | if (r->maxExpansions == NULL) { |
michael@0 | 288 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 289 | goto cleanup; |
michael@0 | 290 | } |
michael@0 | 291 | r->maxExpansions->size = t->maxExpansions->size; |
michael@0 | 292 | r->maxExpansions->position = t->maxExpansions->position; |
michael@0 | 293 | if(t->maxExpansions->endExpansionCE != NULL) { |
michael@0 | 294 | r->maxExpansions->endExpansionCE = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->maxExpansions->size); |
michael@0 | 295 | /* test for NULL */ |
michael@0 | 296 | if (r->maxExpansions->endExpansionCE == NULL) { |
michael@0 | 297 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 298 | goto cleanup; |
michael@0 | 299 | } |
michael@0 | 300 | uprv_memset(r->maxExpansions->endExpansionCE, 0xDB, sizeof(uint32_t)*t->maxExpansions->size); |
michael@0 | 301 | uprv_memcpy(r->maxExpansions->endExpansionCE, t->maxExpansions->endExpansionCE, t->maxExpansions->position*sizeof(uint32_t)); |
michael@0 | 302 | } else { |
michael@0 | 303 | r->maxExpansions->endExpansionCE = NULL; |
michael@0 | 304 | } |
michael@0 | 305 | if(t->maxExpansions->expansionCESize != NULL) { |
michael@0 | 306 | r->maxExpansions->expansionCESize = (uint8_t *)uprv_malloc(sizeof(uint8_t)*t->maxExpansions->size); |
michael@0 | 307 | /* test for NULL */ |
michael@0 | 308 | if (r->maxExpansions->expansionCESize == NULL) { |
michael@0 | 309 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 310 | goto cleanup; |
michael@0 | 311 | } |
michael@0 | 312 | uprv_memset(r->maxExpansions->expansionCESize, 0xDB, sizeof(uint8_t)*t->maxExpansions->size); |
michael@0 | 313 | uprv_memcpy(r->maxExpansions->expansionCESize, t->maxExpansions->expansionCESize, t->maxExpansions->position*sizeof(uint8_t)); |
michael@0 | 314 | } else { |
michael@0 | 315 | r->maxExpansions->expansionCESize = NULL; |
michael@0 | 316 | } |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | if(t->maxJamoExpansions != NULL) { |
michael@0 | 320 | r->maxJamoExpansions = (MaxJamoExpansionTable *)uprv_malloc(sizeof(MaxJamoExpansionTable)); |
michael@0 | 321 | /* test for NULL */ |
michael@0 | 322 | if (r->maxJamoExpansions == NULL) { |
michael@0 | 323 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 324 | goto cleanup; |
michael@0 | 325 | } |
michael@0 | 326 | r->maxJamoExpansions->size = t->maxJamoExpansions->size; |
michael@0 | 327 | r->maxJamoExpansions->position = t->maxJamoExpansions->position; |
michael@0 | 328 | r->maxJamoExpansions->maxLSize = t->maxJamoExpansions->maxLSize; |
michael@0 | 329 | r->maxJamoExpansions->maxVSize = t->maxJamoExpansions->maxVSize; |
michael@0 | 330 | r->maxJamoExpansions->maxTSize = t->maxJamoExpansions->maxTSize; |
michael@0 | 331 | if(t->maxJamoExpansions->size != 0) { |
michael@0 | 332 | r->maxJamoExpansions->endExpansionCE = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->maxJamoExpansions->size); |
michael@0 | 333 | /* test for NULL */ |
michael@0 | 334 | if (r->maxJamoExpansions->endExpansionCE == NULL) { |
michael@0 | 335 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 336 | goto cleanup; |
michael@0 | 337 | } |
michael@0 | 338 | uprv_memcpy(r->maxJamoExpansions->endExpansionCE, t->maxJamoExpansions->endExpansionCE, t->maxJamoExpansions->position*sizeof(uint32_t)); |
michael@0 | 339 | r->maxJamoExpansions->isV = (UBool *)uprv_malloc(sizeof(UBool)*t->maxJamoExpansions->size); |
michael@0 | 340 | /* test for NULL */ |
michael@0 | 341 | if (r->maxJamoExpansions->isV == NULL) { |
michael@0 | 342 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 343 | goto cleanup; |
michael@0 | 344 | } |
michael@0 | 345 | uprv_memcpy(r->maxJamoExpansions->isV, t->maxJamoExpansions->isV, t->maxJamoExpansions->position*sizeof(UBool)); |
michael@0 | 346 | } else { |
michael@0 | 347 | r->maxJamoExpansions->endExpansionCE = NULL; |
michael@0 | 348 | r->maxJamoExpansions->isV = NULL; |
michael@0 | 349 | } |
michael@0 | 350 | } |
michael@0 | 351 | |
michael@0 | 352 | if(t->unsafeCP != NULL) { |
michael@0 | 353 | r->unsafeCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 354 | /* test for NULL */ |
michael@0 | 355 | if (r->unsafeCP == NULL) { |
michael@0 | 356 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 357 | goto cleanup; |
michael@0 | 358 | } |
michael@0 | 359 | uprv_memcpy(r->unsafeCP, t->unsafeCP, UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 360 | } |
michael@0 | 361 | |
michael@0 | 362 | if(t->contrEndCP != NULL) { |
michael@0 | 363 | r->contrEndCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 364 | /* test for NULL */ |
michael@0 | 365 | if (r->contrEndCP == NULL) { |
michael@0 | 366 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 367 | goto cleanup; |
michael@0 | 368 | } |
michael@0 | 369 | uprv_memcpy(r->contrEndCP, t->contrEndCP, UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 370 | } |
michael@0 | 371 | |
michael@0 | 372 | r->UCA = t->UCA; |
michael@0 | 373 | r->image = t->image; |
michael@0 | 374 | r->options = t->options; |
michael@0 | 375 | |
michael@0 | 376 | return r; |
michael@0 | 377 | cleanup: |
michael@0 | 378 | uprv_uca_closeTempTable(t); |
michael@0 | 379 | return NULL; |
michael@0 | 380 | } |
michael@0 | 381 | |
michael@0 | 382 | |
michael@0 | 383 | U_CAPI void U_EXPORT2 |
michael@0 | 384 | uprv_uca_closeTempTable(tempUCATable *t) { |
michael@0 | 385 | if(t != NULL) { |
michael@0 | 386 | if (t->expansions != NULL) { |
michael@0 | 387 | uprv_free(t->expansions->CEs); |
michael@0 | 388 | uprv_free(t->expansions); |
michael@0 | 389 | } |
michael@0 | 390 | if(t->contractions != NULL) { |
michael@0 | 391 | uprv_cnttab_close(t->contractions); |
michael@0 | 392 | } |
michael@0 | 393 | if (t->mapping != NULL) { |
michael@0 | 394 | utrie_close(t->mapping); |
michael@0 | 395 | } |
michael@0 | 396 | |
michael@0 | 397 | if(t->prefixLookup != NULL) { |
michael@0 | 398 | uhash_close(t->prefixLookup); |
michael@0 | 399 | } |
michael@0 | 400 | |
michael@0 | 401 | if (t->maxExpansions != NULL) { |
michael@0 | 402 | uprv_free(t->maxExpansions->endExpansionCE); |
michael@0 | 403 | uprv_free(t->maxExpansions->expansionCESize); |
michael@0 | 404 | uprv_free(t->maxExpansions); |
michael@0 | 405 | } |
michael@0 | 406 | |
michael@0 | 407 | if (t->maxJamoExpansions->size > 0) { |
michael@0 | 408 | uprv_free(t->maxJamoExpansions->endExpansionCE); |
michael@0 | 409 | uprv_free(t->maxJamoExpansions->isV); |
michael@0 | 410 | } |
michael@0 | 411 | uprv_free(t->maxJamoExpansions); |
michael@0 | 412 | |
michael@0 | 413 | uprv_free(t->unsafeCP); |
michael@0 | 414 | uprv_free(t->contrEndCP); |
michael@0 | 415 | |
michael@0 | 416 | if (t->cmLookup != NULL) { |
michael@0 | 417 | uprv_free(t->cmLookup->cPoints); |
michael@0 | 418 | uprv_free(t->cmLookup); |
michael@0 | 419 | } |
michael@0 | 420 | |
michael@0 | 421 | uprv_free(t); |
michael@0 | 422 | } |
michael@0 | 423 | } |
michael@0 | 424 | |
michael@0 | 425 | /** |
michael@0 | 426 | * Looks for the maximum length of all expansion sequences ending with the same |
michael@0 | 427 | * collation element. The size required for maxexpansion and maxsize is |
michael@0 | 428 | * returned if the arrays are too small. |
michael@0 | 429 | * @param endexpansion the last expansion collation element to be added |
michael@0 | 430 | * @param expansionsize size of the expansion |
michael@0 | 431 | * @param maxexpansion data structure to store the maximum expansion data. |
michael@0 | 432 | * @param status error status |
michael@0 | 433 | * @returns size of the maxexpansion and maxsize used. |
michael@0 | 434 | */ |
michael@0 | 435 | static int uprv_uca_setMaxExpansion(uint32_t endexpansion, |
michael@0 | 436 | uint8_t expansionsize, |
michael@0 | 437 | MaxExpansionTable *maxexpansion, |
michael@0 | 438 | UErrorCode *status) |
michael@0 | 439 | { |
michael@0 | 440 | if (maxexpansion->size == 0) { |
michael@0 | 441 | /* we'll always make the first element 0, for easier manipulation */ |
michael@0 | 442 | maxexpansion->endExpansionCE = |
michael@0 | 443 | (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(int32_t)); |
michael@0 | 444 | /* test for NULL */ |
michael@0 | 445 | if (maxexpansion->endExpansionCE == NULL) { |
michael@0 | 446 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 447 | return 0; |
michael@0 | 448 | } |
michael@0 | 449 | *(maxexpansion->endExpansionCE) = 0; |
michael@0 | 450 | maxexpansion->expansionCESize = |
michael@0 | 451 | (uint8_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(uint8_t)); |
michael@0 | 452 | /* test for NULL */; |
michael@0 | 453 | if (maxexpansion->expansionCESize == NULL) { |
michael@0 | 454 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 455 | return 0; |
michael@0 | 456 | } |
michael@0 | 457 | *(maxexpansion->expansionCESize) = 0; |
michael@0 | 458 | maxexpansion->size = INIT_EXP_TABLE_SIZE; |
michael@0 | 459 | maxexpansion->position = 0; |
michael@0 | 460 | } |
michael@0 | 461 | |
michael@0 | 462 | if (maxexpansion->position + 1 == maxexpansion->size) { |
michael@0 | 463 | uint32_t *neweece = (uint32_t *)uprv_realloc(maxexpansion->endExpansionCE, |
michael@0 | 464 | 2 * maxexpansion->size * sizeof(uint32_t)); |
michael@0 | 465 | if (neweece == NULL) { |
michael@0 | 466 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 467 | return 0; |
michael@0 | 468 | } |
michael@0 | 469 | maxexpansion->endExpansionCE = neweece; |
michael@0 | 470 | |
michael@0 | 471 | uint8_t *neweces = (uint8_t *)uprv_realloc(maxexpansion->expansionCESize, |
michael@0 | 472 | 2 * maxexpansion->size * sizeof(uint8_t)); |
michael@0 | 473 | if (neweces == NULL) { |
michael@0 | 474 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 475 | return 0; |
michael@0 | 476 | } |
michael@0 | 477 | maxexpansion->expansionCESize = neweces; |
michael@0 | 478 | maxexpansion->size *= 2; |
michael@0 | 479 | } |
michael@0 | 480 | |
michael@0 | 481 | uint32_t *pendexpansionce = maxexpansion->endExpansionCE; |
michael@0 | 482 | uint8_t *pexpansionsize = maxexpansion->expansionCESize; |
michael@0 | 483 | int pos = maxexpansion->position; |
michael@0 | 484 | |
michael@0 | 485 | uint32_t *start = pendexpansionce; |
michael@0 | 486 | uint32_t *limit = pendexpansionce + pos; |
michael@0 | 487 | |
michael@0 | 488 | /* using binary search to determine if last expansion element is |
michael@0 | 489 | already in the array */ |
michael@0 | 490 | uint32_t *mid; |
michael@0 | 491 | int result = -1; |
michael@0 | 492 | while (start < limit - 1) { |
michael@0 | 493 | mid = start + ((limit - start) >> 1); |
michael@0 | 494 | if (endexpansion <= *mid) { |
michael@0 | 495 | limit = mid; |
michael@0 | 496 | } |
michael@0 | 497 | else { |
michael@0 | 498 | start = mid; |
michael@0 | 499 | } |
michael@0 | 500 | } |
michael@0 | 501 | |
michael@0 | 502 | if (*start == endexpansion) { |
michael@0 | 503 | result = (int)(start - pendexpansionce); |
michael@0 | 504 | } |
michael@0 | 505 | else if (*limit == endexpansion) { |
michael@0 | 506 | result = (int)(limit - pendexpansionce); |
michael@0 | 507 | } |
michael@0 | 508 | |
michael@0 | 509 | if (result > -1) { |
michael@0 | 510 | /* found the ce in expansion, we'll just modify the size if it is |
michael@0 | 511 | smaller */ |
michael@0 | 512 | uint8_t *currentsize = pexpansionsize + result; |
michael@0 | 513 | if (*currentsize < expansionsize) { |
michael@0 | 514 | *currentsize = expansionsize; |
michael@0 | 515 | } |
michael@0 | 516 | } |
michael@0 | 517 | else { |
michael@0 | 518 | /* we'll need to squeeze the value into the array. |
michael@0 | 519 | initial implementation. */ |
michael@0 | 520 | /* shifting the subarray down by 1 */ |
michael@0 | 521 | int shiftsize = (int)((pendexpansionce + pos) - start); |
michael@0 | 522 | uint32_t *shiftpos = start + 1; |
michael@0 | 523 | uint8_t *sizeshiftpos = pexpansionsize + (shiftpos - pendexpansionce); |
michael@0 | 524 | |
michael@0 | 525 | /* okay need to rearrange the array into sorted order */ |
michael@0 | 526 | if (shiftsize == 0 /*|| *(pendexpansionce + pos) < endexpansion*/) { /* the commented part is actually both redundant and dangerous */ |
michael@0 | 527 | *(pendexpansionce + pos + 1) = endexpansion; |
michael@0 | 528 | *(pexpansionsize + pos + 1) = expansionsize; |
michael@0 | 529 | } |
michael@0 | 530 | else { |
michael@0 | 531 | uprv_memmove(shiftpos + 1, shiftpos, shiftsize * sizeof(int32_t)); |
michael@0 | 532 | uprv_memmove(sizeshiftpos + 1, sizeshiftpos, |
michael@0 | 533 | shiftsize * sizeof(uint8_t)); |
michael@0 | 534 | *shiftpos = endexpansion; |
michael@0 | 535 | *sizeshiftpos = expansionsize; |
michael@0 | 536 | } |
michael@0 | 537 | maxexpansion->position ++; |
michael@0 | 538 | |
michael@0 | 539 | #ifdef UCOL_DEBUG |
michael@0 | 540 | int temp; |
michael@0 | 541 | UBool found = FALSE; |
michael@0 | 542 | for (temp = 0; temp < maxexpansion->position; temp ++) { |
michael@0 | 543 | if (pendexpansionce[temp] >= pendexpansionce[temp + 1]) { |
michael@0 | 544 | fprintf(stderr, "expansions %d\n", temp); |
michael@0 | 545 | } |
michael@0 | 546 | if (pendexpansionce[temp] == endexpansion) { |
michael@0 | 547 | found =TRUE; |
michael@0 | 548 | if (pexpansionsize[temp] < expansionsize) { |
michael@0 | 549 | fprintf(stderr, "expansions size %d\n", temp); |
michael@0 | 550 | } |
michael@0 | 551 | } |
michael@0 | 552 | } |
michael@0 | 553 | if (pendexpansionce[temp] == endexpansion) { |
michael@0 | 554 | found =TRUE; |
michael@0 | 555 | if (pexpansionsize[temp] < expansionsize) { |
michael@0 | 556 | fprintf(stderr, "expansions size %d\n", temp); |
michael@0 | 557 | } |
michael@0 | 558 | } |
michael@0 | 559 | if (!found) |
michael@0 | 560 | fprintf(stderr, "expansion not found %d\n", temp); |
michael@0 | 561 | #endif |
michael@0 | 562 | } |
michael@0 | 563 | |
michael@0 | 564 | return maxexpansion->position; |
michael@0 | 565 | } |
michael@0 | 566 | |
michael@0 | 567 | /** |
michael@0 | 568 | * Sets the maximum length of all jamo expansion sequences ending with the same |
michael@0 | 569 | * collation element. The size required for maxexpansion and maxsize is |
michael@0 | 570 | * returned if the arrays are too small. |
michael@0 | 571 | * @param ch the jamo codepoint |
michael@0 | 572 | * @param endexpansion the last expansion collation element to be added |
michael@0 | 573 | * @param expansionsize size of the expansion |
michael@0 | 574 | * @param maxexpansion data structure to store the maximum expansion data. |
michael@0 | 575 | * @param status error status |
michael@0 | 576 | * @returns size of the maxexpansion and maxsize used. |
michael@0 | 577 | */ |
michael@0 | 578 | static int uprv_uca_setMaxJamoExpansion(UChar ch, |
michael@0 | 579 | uint32_t endexpansion, |
michael@0 | 580 | uint8_t expansionsize, |
michael@0 | 581 | MaxJamoExpansionTable *maxexpansion, |
michael@0 | 582 | UErrorCode *status) |
michael@0 | 583 | { |
michael@0 | 584 | UBool isV = TRUE; |
michael@0 | 585 | if (((uint32_t)ch - 0x1100) <= (0x1112 - 0x1100)) { |
michael@0 | 586 | /* determines L for Jamo, doesn't need to store this since it is never |
michael@0 | 587 | at the end of a expansion */ |
michael@0 | 588 | if (maxexpansion->maxLSize < expansionsize) { |
michael@0 | 589 | maxexpansion->maxLSize = expansionsize; |
michael@0 | 590 | } |
michael@0 | 591 | return maxexpansion->position; |
michael@0 | 592 | } |
michael@0 | 593 | |
michael@0 | 594 | if (((uint32_t)ch - 0x1161) <= (0x1175 - 0x1161)) { |
michael@0 | 595 | /* determines V for Jamo */ |
michael@0 | 596 | if (maxexpansion->maxVSize < expansionsize) { |
michael@0 | 597 | maxexpansion->maxVSize = expansionsize; |
michael@0 | 598 | } |
michael@0 | 599 | } |
michael@0 | 600 | |
michael@0 | 601 | if (((uint32_t)ch - 0x11A8) <= (0x11C2 - 0x11A8)) { |
michael@0 | 602 | isV = FALSE; |
michael@0 | 603 | /* determines T for Jamo */ |
michael@0 | 604 | if (maxexpansion->maxTSize < expansionsize) { |
michael@0 | 605 | maxexpansion->maxTSize = expansionsize; |
michael@0 | 606 | } |
michael@0 | 607 | } |
michael@0 | 608 | |
michael@0 | 609 | if (maxexpansion->size == 0) { |
michael@0 | 610 | /* we'll always make the first element 0, for easier manipulation */ |
michael@0 | 611 | maxexpansion->endExpansionCE = |
michael@0 | 612 | (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(uint32_t)); |
michael@0 | 613 | /* test for NULL */; |
michael@0 | 614 | if (maxexpansion->endExpansionCE == NULL) { |
michael@0 | 615 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 616 | return 0; |
michael@0 | 617 | } |
michael@0 | 618 | *(maxexpansion->endExpansionCE) = 0; |
michael@0 | 619 | maxexpansion->isV = |
michael@0 | 620 | (UBool *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(UBool)); |
michael@0 | 621 | /* test for NULL */; |
michael@0 | 622 | if (maxexpansion->isV == NULL) { |
michael@0 | 623 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 624 | uprv_free(maxexpansion->endExpansionCE); |
michael@0 | 625 | maxexpansion->endExpansionCE = NULL; |
michael@0 | 626 | return 0; |
michael@0 | 627 | } |
michael@0 | 628 | *(maxexpansion->isV) = 0; |
michael@0 | 629 | maxexpansion->size = INIT_EXP_TABLE_SIZE; |
michael@0 | 630 | maxexpansion->position = 0; |
michael@0 | 631 | } |
michael@0 | 632 | |
michael@0 | 633 | if (maxexpansion->position + 1 == maxexpansion->size) { |
michael@0 | 634 | maxexpansion->size *= 2; |
michael@0 | 635 | maxexpansion->endExpansionCE = (uint32_t *)uprv_realloc(maxexpansion->endExpansionCE, |
michael@0 | 636 | maxexpansion->size * sizeof(uint32_t)); |
michael@0 | 637 | if (maxexpansion->endExpansionCE == NULL) { |
michael@0 | 638 | #ifdef UCOL_DEBUG |
michael@0 | 639 | fprintf(stderr, "out of memory for maxExpansions\n"); |
michael@0 | 640 | #endif |
michael@0 | 641 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 642 | return 0; |
michael@0 | 643 | } |
michael@0 | 644 | maxexpansion->isV = (UBool *)uprv_realloc(maxexpansion->isV, |
michael@0 | 645 | maxexpansion->size * sizeof(UBool)); |
michael@0 | 646 | if (maxexpansion->isV == NULL) { |
michael@0 | 647 | #ifdef UCOL_DEBUG |
michael@0 | 648 | fprintf(stderr, "out of memory for maxExpansions\n"); |
michael@0 | 649 | #endif |
michael@0 | 650 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 651 | uprv_free(maxexpansion->endExpansionCE); |
michael@0 | 652 | maxexpansion->endExpansionCE = NULL; |
michael@0 | 653 | return 0; |
michael@0 | 654 | } |
michael@0 | 655 | } |
michael@0 | 656 | |
michael@0 | 657 | uint32_t *pendexpansionce = maxexpansion->endExpansionCE; |
michael@0 | 658 | int pos = maxexpansion->position; |
michael@0 | 659 | |
michael@0 | 660 | while (pos > 0) { |
michael@0 | 661 | pos --; |
michael@0 | 662 | if (*(pendexpansionce + pos) == endexpansion) { |
michael@0 | 663 | return maxexpansion->position; |
michael@0 | 664 | } |
michael@0 | 665 | } |
michael@0 | 666 | |
michael@0 | 667 | *(pendexpansionce + maxexpansion->position) = endexpansion; |
michael@0 | 668 | *(maxexpansion->isV + maxexpansion->position) = isV; |
michael@0 | 669 | maxexpansion->position ++; |
michael@0 | 670 | |
michael@0 | 671 | return maxexpansion->position; |
michael@0 | 672 | } |
michael@0 | 673 | |
michael@0 | 674 | |
michael@0 | 675 | static void ContrEndCPSet(uint8_t *table, UChar c) { |
michael@0 | 676 | uint32_t hash; |
michael@0 | 677 | uint8_t *htByte; |
michael@0 | 678 | |
michael@0 | 679 | hash = c; |
michael@0 | 680 | if (hash >= UCOL_UNSAFECP_TABLE_SIZE*8) { |
michael@0 | 681 | hash = (hash & UCOL_UNSAFECP_TABLE_MASK) + 256; |
michael@0 | 682 | } |
michael@0 | 683 | htByte = &table[hash>>3]; |
michael@0 | 684 | *htByte |= (1 << (hash & 7)); |
michael@0 | 685 | } |
michael@0 | 686 | |
michael@0 | 687 | |
michael@0 | 688 | static void unsafeCPSet(uint8_t *table, UChar c) { |
michael@0 | 689 | uint32_t hash; |
michael@0 | 690 | uint8_t *htByte; |
michael@0 | 691 | |
michael@0 | 692 | hash = c; |
michael@0 | 693 | if (hash >= UCOL_UNSAFECP_TABLE_SIZE*8) { |
michael@0 | 694 | if (hash >= 0xd800 && hash <= 0xf8ff) { |
michael@0 | 695 | /* Part of a surrogate, or in private use area. */ |
michael@0 | 696 | /* These don't go in the table */ |
michael@0 | 697 | return; |
michael@0 | 698 | } |
michael@0 | 699 | hash = (hash & UCOL_UNSAFECP_TABLE_MASK) + 256; |
michael@0 | 700 | } |
michael@0 | 701 | htByte = &table[hash>>3]; |
michael@0 | 702 | *htByte |= (1 << (hash & 7)); |
michael@0 | 703 | } |
michael@0 | 704 | |
michael@0 | 705 | static void |
michael@0 | 706 | uprv_uca_createCMTable(tempUCATable *t, int32_t noOfCM, UErrorCode *status) { |
michael@0 | 707 | t->cmLookup = (CombinClassTable *)uprv_malloc(sizeof(CombinClassTable)); |
michael@0 | 708 | if (t->cmLookup==NULL) { |
michael@0 | 709 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 710 | return; |
michael@0 | 711 | } |
michael@0 | 712 | t->cmLookup->cPoints=(UChar *)uprv_malloc(noOfCM*sizeof(UChar)); |
michael@0 | 713 | if (t->cmLookup->cPoints ==NULL) { |
michael@0 | 714 | uprv_free(t->cmLookup); |
michael@0 | 715 | t->cmLookup = NULL; |
michael@0 | 716 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 717 | return; |
michael@0 | 718 | } |
michael@0 | 719 | |
michael@0 | 720 | t->cmLookup->size=noOfCM; |
michael@0 | 721 | uprv_memset(t->cmLookup->index, 0, sizeof(t->cmLookup->index)); |
michael@0 | 722 | |
michael@0 | 723 | return; |
michael@0 | 724 | } |
michael@0 | 725 | |
michael@0 | 726 | static void |
michael@0 | 727 | uprv_uca_copyCMTable(tempUCATable *t, UChar *cm, uint16_t *index) { |
michael@0 | 728 | int32_t count=0; |
michael@0 | 729 | |
michael@0 | 730 | for (int32_t i=0; i<256; ++i) { |
michael@0 | 731 | if (index[i]>0) { |
michael@0 | 732 | // cPoints is ordered by combining class value. |
michael@0 | 733 | uprv_memcpy(t->cmLookup->cPoints+count, cm+(i<<8), index[i]*sizeof(UChar)); |
michael@0 | 734 | count += index[i]; |
michael@0 | 735 | } |
michael@0 | 736 | t->cmLookup->index[i]=count; |
michael@0 | 737 | } |
michael@0 | 738 | return; |
michael@0 | 739 | } |
michael@0 | 740 | |
michael@0 | 741 | /* 1. to the UnsafeCP hash table, add all chars with combining class != 0 */ |
michael@0 | 742 | /* 2. build combining marks table for all chars with combining class != 0 */ |
michael@0 | 743 | static void uprv_uca_unsafeCPAddCCNZ(tempUCATable *t, UErrorCode *status) { |
michael@0 | 744 | |
michael@0 | 745 | UChar c; |
michael@0 | 746 | uint16_t fcd; // Hi byte is lead combining class. lo byte is trailing combing class. |
michael@0 | 747 | UBool buildCMTable = (t->cmLookup==NULL); // flag for building combining class table |
michael@0 | 748 | UChar *cm=NULL; |
michael@0 | 749 | uint16_t index[256]; |
michael@0 | 750 | int32_t count=0; |
michael@0 | 751 | const Normalizer2Impl *nfcImpl = Normalizer2Factory::getNFCImpl(*status); |
michael@0 | 752 | if (U_FAILURE(*status)) { |
michael@0 | 753 | return; |
michael@0 | 754 | } |
michael@0 | 755 | |
michael@0 | 756 | if (buildCMTable) { |
michael@0 | 757 | if (cm==NULL) { |
michael@0 | 758 | cm = (UChar *)uprv_malloc(sizeof(UChar)*UCOL_MAX_CM_TAB); |
michael@0 | 759 | if (cm==NULL) { |
michael@0 | 760 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 761 | return; |
michael@0 | 762 | } |
michael@0 | 763 | } |
michael@0 | 764 | uprv_memset(index, 0, sizeof(index)); |
michael@0 | 765 | } |
michael@0 | 766 | for (c=0; c<0xffff; c++) { |
michael@0 | 767 | if (U16_IS_LEAD(c)) { |
michael@0 | 768 | fcd = 0; |
michael@0 | 769 | if (nfcImpl->singleLeadMightHaveNonZeroFCD16(c)) { |
michael@0 | 770 | UChar32 supp = U16_GET_SUPPLEMENTARY(c, 0xdc00); |
michael@0 | 771 | UChar32 suppLimit = supp + 0x400; |
michael@0 | 772 | while (supp < suppLimit) { |
michael@0 | 773 | fcd |= nfcImpl->getFCD16FromNormData(supp++); |
michael@0 | 774 | } |
michael@0 | 775 | } |
michael@0 | 776 | } else { |
michael@0 | 777 | fcd = nfcImpl->getFCD16(c); |
michael@0 | 778 | } |
michael@0 | 779 | if (fcd >= 0x100 || // if the leading combining class(c) > 0 || |
michael@0 | 780 | (U16_IS_LEAD(c) && fcd != 0)) {// c is a leading surrogate with some FCD data |
michael@0 | 781 | if (buildCMTable) { |
michael@0 | 782 | uint32_t cClass = fcd & 0xff; |
michael@0 | 783 | //uint32_t temp=(cClass<<8)+index[cClass]; |
michael@0 | 784 | cm[(cClass<<8)+index[cClass]] = c; // |
michael@0 | 785 | index[cClass]++; |
michael@0 | 786 | count++; |
michael@0 | 787 | } |
michael@0 | 788 | unsafeCPSet(t->unsafeCP, c); |
michael@0 | 789 | } |
michael@0 | 790 | } |
michael@0 | 791 | |
michael@0 | 792 | // copy to cm table |
michael@0 | 793 | if (buildCMTable) { |
michael@0 | 794 | uprv_uca_createCMTable(t, count, status); |
michael@0 | 795 | if(U_FAILURE(*status)) { |
michael@0 | 796 | if (cm!=NULL) { |
michael@0 | 797 | uprv_free(cm); |
michael@0 | 798 | } |
michael@0 | 799 | return; |
michael@0 | 800 | } |
michael@0 | 801 | uprv_uca_copyCMTable(t, cm, index); |
michael@0 | 802 | } |
michael@0 | 803 | |
michael@0 | 804 | if(t->prefixLookup != NULL) { |
michael@0 | 805 | int32_t i = -1; |
michael@0 | 806 | const UHashElement *e = NULL; |
michael@0 | 807 | UCAElements *element = NULL; |
michael@0 | 808 | UChar NFCbuf[256]; |
michael@0 | 809 | while((e = uhash_nextElement(t->prefixLookup, &i)) != NULL) { |
michael@0 | 810 | element = (UCAElements *)e->value.pointer; |
michael@0 | 811 | // codepoints here are in the NFD form. We need to add the |
michael@0 | 812 | // first code point of the NFC form to unsafe, because |
michael@0 | 813 | // strcoll needs to backup over them. |
michael@0 | 814 | unorm_normalize(element->cPoints, element->cSize, UNORM_NFC, 0, |
michael@0 | 815 | NFCbuf, 256, status); |
michael@0 | 816 | unsafeCPSet(t->unsafeCP, NFCbuf[0]); |
michael@0 | 817 | } |
michael@0 | 818 | } |
michael@0 | 819 | |
michael@0 | 820 | if (cm!=NULL) { |
michael@0 | 821 | uprv_free(cm); |
michael@0 | 822 | } |
michael@0 | 823 | } |
michael@0 | 824 | |
michael@0 | 825 | static uint32_t uprv_uca_addPrefix(tempUCATable *t, uint32_t CE, |
michael@0 | 826 | UCAElements *element, UErrorCode *status) |
michael@0 | 827 | { |
michael@0 | 828 | // currently the longest prefix we're supporting in Japanese is two characters |
michael@0 | 829 | // long. Although this table could quite easily mimic complete contraction stuff |
michael@0 | 830 | // there is no good reason to make a general solution, as it would require some |
michael@0 | 831 | // error prone messing. |
michael@0 | 832 | CntTable *contractions = t->contractions; |
michael@0 | 833 | UChar32 cp; |
michael@0 | 834 | uint32_t cpsize = 0; |
michael@0 | 835 | UChar *oldCP = element->cPoints; |
michael@0 | 836 | uint32_t oldCPSize = element->cSize; |
michael@0 | 837 | |
michael@0 | 838 | |
michael@0 | 839 | contractions->currentTag = SPEC_PROC_TAG; |
michael@0 | 840 | |
michael@0 | 841 | // here, we will normalize & add prefix to the table. |
michael@0 | 842 | uint32_t j = 0; |
michael@0 | 843 | #ifdef UCOL_DEBUG |
michael@0 | 844 | for(j=0; j<element->cSize; j++) { |
michael@0 | 845 | fprintf(stdout, "CP: %04X ", element->cPoints[j]); |
michael@0 | 846 | } |
michael@0 | 847 | fprintf(stdout, "El: %08X Pref: ", CE); |
michael@0 | 848 | for(j=0; j<element->prefixSize; j++) { |
michael@0 | 849 | fprintf(stdout, "%04X ", element->prefix[j]); |
michael@0 | 850 | } |
michael@0 | 851 | fprintf(stdout, "%08X ", element->mapCE); |
michael@0 | 852 | #endif |
michael@0 | 853 | |
michael@0 | 854 | for (j = 1; j<element->prefixSize; j++) { /* First add NFD prefix chars to unsafe CP hash table */ |
michael@0 | 855 | // Unless it is a trail surrogate, which is handled algoritmically and |
michael@0 | 856 | // shouldn't take up space in the table. |
michael@0 | 857 | if(!(U16_IS_TRAIL(element->prefix[j]))) { |
michael@0 | 858 | unsafeCPSet(t->unsafeCP, element->prefix[j]); |
michael@0 | 859 | } |
michael@0 | 860 | } |
michael@0 | 861 | |
michael@0 | 862 | UChar tempPrefix = 0; |
michael@0 | 863 | |
michael@0 | 864 | for(j = 0; j < /*nfcSize*/element->prefixSize/2; j++) { // prefixes are going to be looked up backwards |
michael@0 | 865 | // therefore, we will promptly reverse the prefix buffer... |
michael@0 | 866 | tempPrefix = *(/*nfcBuffer*/element->prefix+element->prefixSize-j-1); |
michael@0 | 867 | *(/*nfcBuffer*/element->prefix+element->prefixSize-j-1) = element->prefix[j]; |
michael@0 | 868 | element->prefix[j] = tempPrefix; |
michael@0 | 869 | } |
michael@0 | 870 | |
michael@0 | 871 | #ifdef UCOL_DEBUG |
michael@0 | 872 | fprintf(stdout, "Reversed: "); |
michael@0 | 873 | for(j=0; j<element->prefixSize; j++) { |
michael@0 | 874 | fprintf(stdout, "%04X ", element->prefix[j]); |
michael@0 | 875 | } |
michael@0 | 876 | fprintf(stdout, "%08X\n", element->mapCE); |
michael@0 | 877 | #endif |
michael@0 | 878 | |
michael@0 | 879 | // the first codepoint is also unsafe, as it forms a 'contraction' with the prefix |
michael@0 | 880 | if(!(U16_IS_TRAIL(element->cPoints[0]))) { |
michael@0 | 881 | unsafeCPSet(t->unsafeCP, element->cPoints[0]); |
michael@0 | 882 | } |
michael@0 | 883 | |
michael@0 | 884 | // Maybe we need this... To handle prefixes completely in the forward direction... |
michael@0 | 885 | //if(element->cSize == 1) { |
michael@0 | 886 | // if(!(U16_IS_TRAIL(element->cPoints[0]))) { |
michael@0 | 887 | // ContrEndCPSet(t->contrEndCP, element->cPoints[0]); |
michael@0 | 888 | // } |
michael@0 | 889 | //} |
michael@0 | 890 | |
michael@0 | 891 | element->cPoints = element->prefix; |
michael@0 | 892 | element->cSize = element->prefixSize; |
michael@0 | 893 | |
michael@0 | 894 | // Add the last char of the contraction to the contraction-end hash table. |
michael@0 | 895 | // unless it is a trail surrogate, which is handled algorithmically and |
michael@0 | 896 | // shouldn't be in the table |
michael@0 | 897 | if(!(U16_IS_TRAIL(element->cPoints[element->cSize -1]))) { |
michael@0 | 898 | ContrEndCPSet(t->contrEndCP, element->cPoints[element->cSize -1]); |
michael@0 | 899 | } |
michael@0 | 900 | |
michael@0 | 901 | // First we need to check if contractions starts with a surrogate |
michael@0 | 902 | U16_NEXT(element->cPoints, cpsize, element->cSize, cp); |
michael@0 | 903 | |
michael@0 | 904 | // If there are any Jamos in the contraction, we should turn on special |
michael@0 | 905 | // processing for Jamos |
michael@0 | 906 | if(UCOL_ISJAMO(element->prefix[0])) { |
michael@0 | 907 | t->image->jamoSpecial = TRUE; |
michael@0 | 908 | } |
michael@0 | 909 | /* then we need to deal with it */ |
michael@0 | 910 | /* we could aready have something in table - or we might not */ |
michael@0 | 911 | |
michael@0 | 912 | if(!isPrefix(CE)) { |
michael@0 | 913 | /* if it wasn't contraction, we wouldn't end up here*/ |
michael@0 | 914 | int32_t firstContractionOffset = 0; |
michael@0 | 915 | firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, CE, status); |
michael@0 | 916 | uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); |
michael@0 | 917 | uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->prefix, newCE, status); |
michael@0 | 918 | uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, CE, status); |
michael@0 | 919 | CE = constructContractCE(SPEC_PROC_TAG, firstContractionOffset); |
michael@0 | 920 | } else { /* we are adding to existing contraction */ |
michael@0 | 921 | /* there were already some elements in the table, so we need to add a new contraction */ |
michael@0 | 922 | /* Two things can happen here: either the codepoint is already in the table, or it is not */ |
michael@0 | 923 | int32_t position = uprv_cnttab_findCP(contractions, CE, *element->prefix, status); |
michael@0 | 924 | if(position > 0) { /* if it is we just continue down the chain */ |
michael@0 | 925 | uint32_t eCE = uprv_cnttab_getCE(contractions, CE, position, status); |
michael@0 | 926 | uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status); |
michael@0 | 927 | uprv_cnttab_setContraction(contractions, CE, position, *(element->prefix), newCE, status); |
michael@0 | 928 | } else { /* if it isn't, we will have to create a new sequence */ |
michael@0 | 929 | uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); |
michael@0 | 930 | uprv_cnttab_insertContraction(contractions, CE, *(element->prefix), element->mapCE, status); |
michael@0 | 931 | } |
michael@0 | 932 | } |
michael@0 | 933 | |
michael@0 | 934 | element->cPoints = oldCP; |
michael@0 | 935 | element->cSize = oldCPSize; |
michael@0 | 936 | |
michael@0 | 937 | return CE; |
michael@0 | 938 | } |
michael@0 | 939 | |
michael@0 | 940 | // Note regarding surrogate handling: We are interested only in the single |
michael@0 | 941 | // or leading surrogates in a contraction. If a surrogate is somewhere else |
michael@0 | 942 | // in the contraction, it is going to be handled as a pair of code units, |
michael@0 | 943 | // as it doesn't affect the performance AND handling surrogates specially |
michael@0 | 944 | // would complicate code way too much. |
michael@0 | 945 | static uint32_t uprv_uca_addContraction(tempUCATable *t, uint32_t CE, |
michael@0 | 946 | UCAElements *element, UErrorCode *status) |
michael@0 | 947 | { |
michael@0 | 948 | CntTable *contractions = t->contractions; |
michael@0 | 949 | UChar32 cp; |
michael@0 | 950 | uint32_t cpsize = 0; |
michael@0 | 951 | |
michael@0 | 952 | contractions->currentTag = CONTRACTION_TAG; |
michael@0 | 953 | |
michael@0 | 954 | // First we need to check if contractions starts with a surrogate |
michael@0 | 955 | U16_NEXT(element->cPoints, cpsize, element->cSize, cp); |
michael@0 | 956 | |
michael@0 | 957 | if(cpsize<element->cSize) { // This is a real contraction, if there are other characters after the first |
michael@0 | 958 | uint32_t j = 0; |
michael@0 | 959 | for (j=1; j<element->cSize; j++) { /* First add contraction chars to unsafe CP hash table */ |
michael@0 | 960 | // Unless it is a trail surrogate, which is handled algoritmically and |
michael@0 | 961 | // shouldn't take up space in the table. |
michael@0 | 962 | if(!(U16_IS_TRAIL(element->cPoints[j]))) { |
michael@0 | 963 | unsafeCPSet(t->unsafeCP, element->cPoints[j]); |
michael@0 | 964 | } |
michael@0 | 965 | } |
michael@0 | 966 | // Add the last char of the contraction to the contraction-end hash table. |
michael@0 | 967 | // unless it is a trail surrogate, which is handled algorithmically and |
michael@0 | 968 | // shouldn't be in the table |
michael@0 | 969 | if(!(U16_IS_TRAIL(element->cPoints[element->cSize -1]))) { |
michael@0 | 970 | ContrEndCPSet(t->contrEndCP, element->cPoints[element->cSize -1]); |
michael@0 | 971 | } |
michael@0 | 972 | |
michael@0 | 973 | // If there are any Jamos in the contraction, we should turn on special |
michael@0 | 974 | // processing for Jamos |
michael@0 | 975 | if(UCOL_ISJAMO(element->cPoints[0])) { |
michael@0 | 976 | t->image->jamoSpecial = TRUE; |
michael@0 | 977 | } |
michael@0 | 978 | /* then we need to deal with it */ |
michael@0 | 979 | /* we could aready have something in table - or we might not */ |
michael@0 | 980 | element->cPoints+=cpsize; |
michael@0 | 981 | element->cSize-=cpsize; |
michael@0 | 982 | if(!isContraction(CE)) { |
michael@0 | 983 | /* if it wasn't contraction, we wouldn't end up here*/ |
michael@0 | 984 | int32_t firstContractionOffset = 0; |
michael@0 | 985 | firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, CE, status); |
michael@0 | 986 | uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); |
michael@0 | 987 | uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->cPoints, newCE, status); |
michael@0 | 988 | uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, CE, status); |
michael@0 | 989 | CE = constructContractCE(CONTRACTION_TAG, firstContractionOffset); |
michael@0 | 990 | } else { /* we are adding to existing contraction */ |
michael@0 | 991 | /* there were already some elements in the table, so we need to add a new contraction */ |
michael@0 | 992 | /* Two things can happen here: either the codepoint is already in the table, or it is not */ |
michael@0 | 993 | int32_t position = uprv_cnttab_findCP(contractions, CE, *element->cPoints, status); |
michael@0 | 994 | if(position > 0) { /* if it is we just continue down the chain */ |
michael@0 | 995 | uint32_t eCE = uprv_cnttab_getCE(contractions, CE, position, status); |
michael@0 | 996 | uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status); |
michael@0 | 997 | uprv_cnttab_setContraction(contractions, CE, position, *(element->cPoints), newCE, status); |
michael@0 | 998 | } else { /* if it isn't, we will have to create a new sequence */ |
michael@0 | 999 | uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); |
michael@0 | 1000 | uprv_cnttab_insertContraction(contractions, CE, *(element->cPoints), newCE, status); |
michael@0 | 1001 | } |
michael@0 | 1002 | } |
michael@0 | 1003 | element->cPoints-=cpsize; |
michael@0 | 1004 | element->cSize+=cpsize; |
michael@0 | 1005 | /*ucmpe32_set(t->mapping, cp, CE);*/ |
michael@0 | 1006 | utrie_set32(t->mapping, cp, CE); |
michael@0 | 1007 | } else if(!isContraction(CE)) { /* this is just a surrogate, and there is no contraction */ |
michael@0 | 1008 | /*ucmpe32_set(t->mapping, cp, element->mapCE);*/ |
michael@0 | 1009 | utrie_set32(t->mapping, cp, element->mapCE); |
michael@0 | 1010 | } else { /* fill out the first stage of the contraction with the surrogate CE */ |
michael@0 | 1011 | uprv_cnttab_changeContraction(contractions, CE, 0, element->mapCE, status); |
michael@0 | 1012 | uprv_cnttab_changeContraction(contractions, CE, 0xFFFF, element->mapCE, status); |
michael@0 | 1013 | } |
michael@0 | 1014 | return CE; |
michael@0 | 1015 | } |
michael@0 | 1016 | |
michael@0 | 1017 | |
michael@0 | 1018 | static uint32_t uprv_uca_processContraction(CntTable *contractions, UCAElements *element, uint32_t existingCE, UErrorCode *status) { |
michael@0 | 1019 | int32_t firstContractionOffset = 0; |
michael@0 | 1020 | // uint32_t contractionElement = UCOL_NOT_FOUND; |
michael@0 | 1021 | |
michael@0 | 1022 | if(U_FAILURE(*status)) { |
michael@0 | 1023 | return UCOL_NOT_FOUND; |
michael@0 | 1024 | } |
michael@0 | 1025 | |
michael@0 | 1026 | /* end of recursion */ |
michael@0 | 1027 | if(element->cSize == 1) { |
michael@0 | 1028 | if(isCntTableElement(existingCE) && ((UColCETags)getCETag(existingCE) == contractions->currentTag)) { |
michael@0 | 1029 | uprv_cnttab_changeContraction(contractions, existingCE, 0, element->mapCE, status); |
michael@0 | 1030 | uprv_cnttab_changeContraction(contractions, existingCE, 0xFFFF, element->mapCE, status); |
michael@0 | 1031 | return existingCE; |
michael@0 | 1032 | } else { |
michael@0 | 1033 | return element->mapCE; /*can't do just that. existingCe might be a contraction, meaning that we need to do another step */ |
michael@0 | 1034 | } |
michael@0 | 1035 | } |
michael@0 | 1036 | |
michael@0 | 1037 | /* this recursion currently feeds on the only element we have... We will have to copy it in order to accomodate */ |
michael@0 | 1038 | /* for both backward and forward cycles */ |
michael@0 | 1039 | |
michael@0 | 1040 | /* we encountered either an empty space or a non-contraction element */ |
michael@0 | 1041 | /* this means we are constructing a new contraction sequence */ |
michael@0 | 1042 | element->cPoints++; |
michael@0 | 1043 | element->cSize--; |
michael@0 | 1044 | if(!isCntTableElement(existingCE)) { |
michael@0 | 1045 | /* if it wasn't contraction, we wouldn't end up here*/ |
michael@0 | 1046 | firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, existingCE, status); |
michael@0 | 1047 | uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); |
michael@0 | 1048 | uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->cPoints, newCE, status); |
michael@0 | 1049 | uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, existingCE, status); |
michael@0 | 1050 | existingCE = constructContractCE(contractions->currentTag, firstContractionOffset); |
michael@0 | 1051 | } else { /* we are adding to existing contraction */ |
michael@0 | 1052 | /* there were already some elements in the table, so we need to add a new contraction */ |
michael@0 | 1053 | /* Two things can happen here: either the codepoint is already in the table, or it is not */ |
michael@0 | 1054 | int32_t position = uprv_cnttab_findCP(contractions, existingCE, *element->cPoints, status); |
michael@0 | 1055 | if(position > 0) { /* if it is we just continue down the chain */ |
michael@0 | 1056 | uint32_t eCE = uprv_cnttab_getCE(contractions, existingCE, position, status); |
michael@0 | 1057 | uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status); |
michael@0 | 1058 | uprv_cnttab_setContraction(contractions, existingCE, position, *(element->cPoints), newCE, status); |
michael@0 | 1059 | } else { /* if it isn't, we will have to create a new sequence */ |
michael@0 | 1060 | uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status); |
michael@0 | 1061 | uprv_cnttab_insertContraction(contractions, existingCE, *(element->cPoints), newCE, status); |
michael@0 | 1062 | } |
michael@0 | 1063 | } |
michael@0 | 1064 | element->cPoints--; |
michael@0 | 1065 | element->cSize++; |
michael@0 | 1066 | return existingCE; |
michael@0 | 1067 | } |
michael@0 | 1068 | |
michael@0 | 1069 | static uint32_t uprv_uca_finalizeAddition(tempUCATable *t, UCAElements *element, UErrorCode *status) { |
michael@0 | 1070 | uint32_t CE = UCOL_NOT_FOUND; |
michael@0 | 1071 | // This should add a completely ignorable element to the |
michael@0 | 1072 | // unsafe table, so that backward iteration will skip |
michael@0 | 1073 | // over it when treating contractions. |
michael@0 | 1074 | uint32_t i = 0; |
michael@0 | 1075 | if(element->mapCE == 0) { |
michael@0 | 1076 | for(i = 0; i < element->cSize; i++) { |
michael@0 | 1077 | if(!U16_IS_TRAIL(element->cPoints[i])) { |
michael@0 | 1078 | unsafeCPSet(t->unsafeCP, element->cPoints[i]); |
michael@0 | 1079 | } |
michael@0 | 1080 | } |
michael@0 | 1081 | } |
michael@0 | 1082 | if(element->cSize > 1) { /* we're adding a contraction */ |
michael@0 | 1083 | uint32_t i = 0; |
michael@0 | 1084 | UChar32 cp; |
michael@0 | 1085 | |
michael@0 | 1086 | U16_NEXT(element->cPoints, i, element->cSize, cp); |
michael@0 | 1087 | /*CE = ucmpe32_get(t->mapping, cp);*/ |
michael@0 | 1088 | CE = utrie_get32(t->mapping, cp, NULL); |
michael@0 | 1089 | |
michael@0 | 1090 | CE = uprv_uca_addContraction(t, CE, element, status); |
michael@0 | 1091 | } else { /* easy case, */ |
michael@0 | 1092 | /*CE = ucmpe32_get(t->mapping, element->cPoints[0]);*/ |
michael@0 | 1093 | CE = utrie_get32(t->mapping, element->cPoints[0], NULL); |
michael@0 | 1094 | |
michael@0 | 1095 | if( CE != UCOL_NOT_FOUND) { |
michael@0 | 1096 | if(isCntTableElement(CE) /*isContraction(CE)*/) { /* adding a non contraction element (thai, expansion, single) to already existing contraction */ |
michael@0 | 1097 | if(!isPrefix(element->mapCE)) { // we cannot reenter prefix elements - as we are going to create a dead loop |
michael@0 | 1098 | // Only expansions and regular CEs can go here... Contractions will never happen in this place |
michael@0 | 1099 | uprv_cnttab_setContraction(t->contractions, CE, 0, 0, element->mapCE, status); |
michael@0 | 1100 | /* This loop has to change the CE at the end of contraction REDO!*/ |
michael@0 | 1101 | uprv_cnttab_changeLastCE(t->contractions, CE, element->mapCE, status); |
michael@0 | 1102 | } |
michael@0 | 1103 | } else { |
michael@0 | 1104 | /*ucmpe32_set(t->mapping, element->cPoints[0], element->mapCE);*/ |
michael@0 | 1105 | utrie_set32(t->mapping, element->cPoints[0], element->mapCE); |
michael@0 | 1106 | if ((element->prefixSize!=0) && (!isSpecial(CE) || (getCETag(CE)!=IMPLICIT_TAG))) { |
michael@0 | 1107 | UCAElements *origElem = (UCAElements *)uprv_malloc(sizeof(UCAElements)); |
michael@0 | 1108 | /* test for NULL */ |
michael@0 | 1109 | if (origElem== NULL) { |
michael@0 | 1110 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 1111 | return 0; |
michael@0 | 1112 | } |
michael@0 | 1113 | /* copy the original UCA value */ |
michael@0 | 1114 | origElem->prefixSize = 0; |
michael@0 | 1115 | origElem->prefix = NULL; |
michael@0 | 1116 | origElem->cPoints = origElem->uchars; |
michael@0 | 1117 | origElem->cPoints[0] = element->cPoints[0]; |
michael@0 | 1118 | origElem->cSize = 1; |
michael@0 | 1119 | origElem->CEs[0]=CE; |
michael@0 | 1120 | origElem->mapCE=CE; |
michael@0 | 1121 | origElem->noOfCEs=1; |
michael@0 | 1122 | uprv_uca_finalizeAddition(t, origElem, status); |
michael@0 | 1123 | uprv_free(origElem); |
michael@0 | 1124 | } |
michael@0 | 1125 | #ifdef UCOL_DEBUG |
michael@0 | 1126 | fprintf(stderr, "Warning - trying to overwrite existing data %08X for cp %04X with %08X\n", CE, element->cPoints[0], element->CEs[0]); |
michael@0 | 1127 | //*status = U_ILLEGAL_ARGUMENT_ERROR; |
michael@0 | 1128 | #endif |
michael@0 | 1129 | } |
michael@0 | 1130 | } else { |
michael@0 | 1131 | /*ucmpe32_set(t->mapping, element->cPoints[0], element->mapCE);*/ |
michael@0 | 1132 | utrie_set32(t->mapping, element->cPoints[0], element->mapCE); |
michael@0 | 1133 | } |
michael@0 | 1134 | } |
michael@0 | 1135 | return CE; |
michael@0 | 1136 | } |
michael@0 | 1137 | |
michael@0 | 1138 | /* This adds a read element, while testing for existence */ |
michael@0 | 1139 | U_CAPI uint32_t U_EXPORT2 |
michael@0 | 1140 | uprv_uca_addAnElement(tempUCATable *t, UCAElements *element, UErrorCode *status) { |
michael@0 | 1141 | U_NAMESPACE_USE |
michael@0 | 1142 | |
michael@0 | 1143 | ExpansionTable *expansions = t->expansions; |
michael@0 | 1144 | |
michael@0 | 1145 | uint32_t i = 1; |
michael@0 | 1146 | uint32_t expansion = 0; |
michael@0 | 1147 | uint32_t CE; |
michael@0 | 1148 | |
michael@0 | 1149 | if(U_FAILURE(*status)) { |
michael@0 | 1150 | return 0xFFFF; |
michael@0 | 1151 | } |
michael@0 | 1152 | |
michael@0 | 1153 | element->mapCE = 0; // clear mapCE so that we can catch expansions |
michael@0 | 1154 | |
michael@0 | 1155 | if(element->noOfCEs == 1) { |
michael@0 | 1156 | element->mapCE = element->CEs[0]; |
michael@0 | 1157 | } else { |
michael@0 | 1158 | /* ICU 2.1 long primaries */ |
michael@0 | 1159 | /* unfortunately, it looks like we have to look for a long primary here */ |
michael@0 | 1160 | /* since in canonical closure we are going to hit some long primaries from */ |
michael@0 | 1161 | /* the first phase, and they will come back as continuations/expansions */ |
michael@0 | 1162 | /* destroying the effect of the previous opitimization */ |
michael@0 | 1163 | /* A long primary is a three byte primary with starting secondaries and tertiaries */ |
michael@0 | 1164 | /* It can appear in long runs of only primary differences (like east Asian tailorings) */ |
michael@0 | 1165 | /* also, it should not be an expansion, as expansions would break with this */ |
michael@0 | 1166 | // This part came in from ucol_bld.cpp |
michael@0 | 1167 | //if(tok->expansion == 0 |
michael@0 | 1168 | //&& noOfBytes[0] == 3 && noOfBytes[1] == 1 && noOfBytes[2] == 1 |
michael@0 | 1169 | //&& CEparts[1] == (UCOL_BYTE_COMMON << 24) && CEparts[2] == (UCOL_BYTE_COMMON << 24)) { |
michael@0 | 1170 | /* we will construct a special CE that will go unchanged to the table */ |
michael@0 | 1171 | if(element->noOfCEs == 2 // a two CE expansion |
michael@0 | 1172 | && isContinuation(element->CEs[1]) // which is a continuation |
michael@0 | 1173 | && (element->CEs[1] & (~(0xFF << 24 | UCOL_CONTINUATION_MARKER))) == 0 // that has only primaries in continuation, |
michael@0 | 1174 | && (((element->CEs[0]>>8) & 0xFF) == UCOL_BYTE_COMMON) // a common secondary |
michael@0 | 1175 | && ((element->CEs[0] & 0xFF) == UCOL_BYTE_COMMON) // and a common tertiary |
michael@0 | 1176 | ) |
michael@0 | 1177 | { |
michael@0 | 1178 | #ifdef UCOL_DEBUG |
michael@0 | 1179 | fprintf(stdout, "Long primary %04X\n", element->cPoints[0]); |
michael@0 | 1180 | #endif |
michael@0 | 1181 | element->mapCE = UCOL_SPECIAL_FLAG | (LONG_PRIMARY_TAG<<24) // a long primary special |
michael@0 | 1182 | | ((element->CEs[0]>>8) & 0xFFFF00) // first and second byte of primary |
michael@0 | 1183 | | ((element->CEs[1]>>24) & 0xFF); // third byte of primary |
michael@0 | 1184 | } |
michael@0 | 1185 | else { |
michael@0 | 1186 | expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (EXPANSION_TAG<<UCOL_TAG_SHIFT) |
michael@0 | 1187 | | (((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4) |
michael@0 | 1188 | & 0xFFFFF0)); |
michael@0 | 1189 | |
michael@0 | 1190 | for(i = 1; i<element->noOfCEs; i++) { |
michael@0 | 1191 | uprv_uca_addExpansion(expansions, element->CEs[i], status); |
michael@0 | 1192 | } |
michael@0 | 1193 | if(element->noOfCEs <= 0xF) { |
michael@0 | 1194 | expansion |= element->noOfCEs; |
michael@0 | 1195 | } else { |
michael@0 | 1196 | uprv_uca_addExpansion(expansions, 0, status); |
michael@0 | 1197 | } |
michael@0 | 1198 | element->mapCE = expansion; |
michael@0 | 1199 | uprv_uca_setMaxExpansion(element->CEs[element->noOfCEs - 1], |
michael@0 | 1200 | (uint8_t)element->noOfCEs, |
michael@0 | 1201 | t->maxExpansions, |
michael@0 | 1202 | status); |
michael@0 | 1203 | if(UCOL_ISJAMO(element->cPoints[0])) { |
michael@0 | 1204 | t->image->jamoSpecial = TRUE; |
michael@0 | 1205 | uprv_uca_setMaxJamoExpansion(element->cPoints[0], |
michael@0 | 1206 | element->CEs[element->noOfCEs - 1], |
michael@0 | 1207 | (uint8_t)element->noOfCEs, |
michael@0 | 1208 | t->maxJamoExpansions, |
michael@0 | 1209 | status); |
michael@0 | 1210 | } |
michael@0 | 1211 | if (U_FAILURE(*status)) { |
michael@0 | 1212 | return 0; |
michael@0 | 1213 | } |
michael@0 | 1214 | } |
michael@0 | 1215 | } |
michael@0 | 1216 | |
michael@0 | 1217 | // We treat digits differently - they are "uber special" and should be |
michael@0 | 1218 | // processed differently if numeric collation is on. |
michael@0 | 1219 | UChar32 uniChar = 0; |
michael@0 | 1220 | //printElement(element); |
michael@0 | 1221 | if ((element->cSize == 2) && U16_IS_LEAD(element->cPoints[0])){ |
michael@0 | 1222 | uniChar = U16_GET_SUPPLEMENTARY(element->cPoints[0], element->cPoints[1]); |
michael@0 | 1223 | } else if (element->cSize == 1){ |
michael@0 | 1224 | uniChar = element->cPoints[0]; |
michael@0 | 1225 | } |
michael@0 | 1226 | |
michael@0 | 1227 | // Here, we either have one normal CE OR mapCE is set. Therefore, we stuff only |
michael@0 | 1228 | // one element to the expansion buffer. When we encounter a digit and we don't |
michael@0 | 1229 | // do numeric collation, we will just pick the CE we have and break out of case |
michael@0 | 1230 | // (see ucol.cpp ucol_prv_getSpecialCE && ucol_prv_getSpecialPrevCE). If we picked |
michael@0 | 1231 | // a special, further processing will occur. If it's a simple CE, we'll return due |
michael@0 | 1232 | // to how the loop is constructed. |
michael@0 | 1233 | if (uniChar != 0 && u_isdigit(uniChar)){ |
michael@0 | 1234 | expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (DIGIT_TAG<<UCOL_TAG_SHIFT) | 1); // prepare the element |
michael@0 | 1235 | if(element->mapCE) { // if there is an expansion, we'll pick it here |
michael@0 | 1236 | expansion |= ((uprv_uca_addExpansion(expansions, element->mapCE, status)+(headersize>>2))<<4); |
michael@0 | 1237 | } else { |
michael@0 | 1238 | expansion |= ((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4); |
michael@0 | 1239 | } |
michael@0 | 1240 | element->mapCE = expansion; |
michael@0 | 1241 | |
michael@0 | 1242 | // Need to go back to the beginning of the digit string if in the middle! |
michael@0 | 1243 | if(uniChar <= 0xFFFF) { // supplementaries are always unsafe. API takes UChars |
michael@0 | 1244 | unsafeCPSet(t->unsafeCP, (UChar)uniChar); |
michael@0 | 1245 | } |
michael@0 | 1246 | } |
michael@0 | 1247 | |
michael@0 | 1248 | // here we want to add the prefix structure. |
michael@0 | 1249 | // I will try to process it as a reverse contraction, if possible. |
michael@0 | 1250 | // prefix buffer is already reversed. |
michael@0 | 1251 | |
michael@0 | 1252 | if(element->prefixSize!=0) { |
michael@0 | 1253 | // We keep the seen prefix starter elements in a hashtable |
michael@0 | 1254 | // we need it to be able to distinguish between the simple |
michael@0 | 1255 | // codepoints and prefix starters. Also, we need to use it |
michael@0 | 1256 | // for canonical closure. |
michael@0 | 1257 | |
michael@0 | 1258 | UCAElements *composed = (UCAElements *)uprv_malloc(sizeof(UCAElements)); |
michael@0 | 1259 | /* test for NULL */ |
michael@0 | 1260 | if (composed == NULL) { |
michael@0 | 1261 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 1262 | return 0; |
michael@0 | 1263 | } |
michael@0 | 1264 | uprv_memcpy(composed, element, sizeof(UCAElements)); |
michael@0 | 1265 | composed->cPoints = composed->uchars; |
michael@0 | 1266 | composed->prefix = composed->prefixChars; |
michael@0 | 1267 | |
michael@0 | 1268 | composed->prefixSize = unorm_normalize(element->prefix, element->prefixSize, UNORM_NFC, 0, composed->prefix, 128, status); |
michael@0 | 1269 | |
michael@0 | 1270 | |
michael@0 | 1271 | if(t->prefixLookup != NULL) { |
michael@0 | 1272 | UCAElements *uCE = (UCAElements *)uhash_get(t->prefixLookup, element); |
michael@0 | 1273 | if(uCE != NULL) { // there is already a set of code points here |
michael@0 | 1274 | element->mapCE = uprv_uca_addPrefix(t, uCE->mapCE, element, status); |
michael@0 | 1275 | } else { // no code points, so this spot is clean |
michael@0 | 1276 | element->mapCE = uprv_uca_addPrefix(t, UCOL_NOT_FOUND, element, status); |
michael@0 | 1277 | uCE = (UCAElements *)uprv_malloc(sizeof(UCAElements)); |
michael@0 | 1278 | /* test for NULL */ |
michael@0 | 1279 | if (uCE == NULL) { |
michael@0 | 1280 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 1281 | return 0; |
michael@0 | 1282 | } |
michael@0 | 1283 | uprv_memcpy(uCE, element, sizeof(UCAElements)); |
michael@0 | 1284 | uCE->cPoints = uCE->uchars; |
michael@0 | 1285 | uhash_put(t->prefixLookup, uCE, uCE, status); |
michael@0 | 1286 | } |
michael@0 | 1287 | if(composed->prefixSize != element->prefixSize || uprv_memcmp(composed->prefix, element->prefix, element->prefixSize)) { |
michael@0 | 1288 | // do it! |
michael@0 | 1289 | composed->mapCE = uprv_uca_addPrefix(t, element->mapCE, composed, status); |
michael@0 | 1290 | } |
michael@0 | 1291 | } |
michael@0 | 1292 | uprv_free(composed); |
michael@0 | 1293 | } |
michael@0 | 1294 | |
michael@0 | 1295 | // We need to use the canonical iterator here |
michael@0 | 1296 | // the way we do it is to generate the canonically equivalent strings |
michael@0 | 1297 | // for the contraction and then add the sequences that pass FCD check |
michael@0 | 1298 | 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 | 1299 | UnicodeString source(element->cPoints, element->cSize); |
michael@0 | 1300 | CanonicalIterator it(source, *status); |
michael@0 | 1301 | source = it.next(); |
michael@0 | 1302 | while(!source.isBogus()) { |
michael@0 | 1303 | if(Normalizer::quickCheck(source, UNORM_FCD, *status) != UNORM_NO) { |
michael@0 | 1304 | element->cSize = source.extract(element->cPoints, 128, *status); |
michael@0 | 1305 | uprv_uca_finalizeAddition(t, element, status); |
michael@0 | 1306 | } |
michael@0 | 1307 | source = it.next(); |
michael@0 | 1308 | } |
michael@0 | 1309 | CE = element->mapCE; |
michael@0 | 1310 | } else { |
michael@0 | 1311 | CE = uprv_uca_finalizeAddition(t, element, status); |
michael@0 | 1312 | } |
michael@0 | 1313 | |
michael@0 | 1314 | return CE; |
michael@0 | 1315 | } |
michael@0 | 1316 | |
michael@0 | 1317 | |
michael@0 | 1318 | /*void uprv_uca_getMaxExpansionJamo(CompactEIntArray *mapping, */ |
michael@0 | 1319 | static void uprv_uca_getMaxExpansionJamo(UNewTrie *mapping, |
michael@0 | 1320 | MaxExpansionTable *maxexpansion, |
michael@0 | 1321 | MaxJamoExpansionTable *maxjamoexpansion, |
michael@0 | 1322 | UBool jamospecial, |
michael@0 | 1323 | UErrorCode *status) |
michael@0 | 1324 | { |
michael@0 | 1325 | const uint32_t VBASE = 0x1161; |
michael@0 | 1326 | const uint32_t TBASE = 0x11A8; |
michael@0 | 1327 | const uint32_t VCOUNT = 21; |
michael@0 | 1328 | const uint32_t TCOUNT = 28; |
michael@0 | 1329 | |
michael@0 | 1330 | uint32_t v = VBASE + VCOUNT - 1; |
michael@0 | 1331 | uint32_t t = TBASE + TCOUNT - 1; |
michael@0 | 1332 | uint32_t ce; |
michael@0 | 1333 | |
michael@0 | 1334 | while (v >= VBASE) { |
michael@0 | 1335 | /*ce = ucmpe32_get(mapping, v);*/ |
michael@0 | 1336 | ce = utrie_get32(mapping, v, NULL); |
michael@0 | 1337 | if (ce < UCOL_SPECIAL_FLAG) { |
michael@0 | 1338 | uprv_uca_setMaxExpansion(ce, 2, maxexpansion, status); |
michael@0 | 1339 | } |
michael@0 | 1340 | v --; |
michael@0 | 1341 | } |
michael@0 | 1342 | |
michael@0 | 1343 | while (t >= TBASE) |
michael@0 | 1344 | { |
michael@0 | 1345 | /*ce = ucmpe32_get(mapping, t);*/ |
michael@0 | 1346 | ce = utrie_get32(mapping, t, NULL); |
michael@0 | 1347 | if (ce < UCOL_SPECIAL_FLAG) { |
michael@0 | 1348 | uprv_uca_setMaxExpansion(ce, 3, maxexpansion, status); |
michael@0 | 1349 | } |
michael@0 | 1350 | t --; |
michael@0 | 1351 | } |
michael@0 | 1352 | /* According to the docs, 99% of the time, the Jamo will not be special */ |
michael@0 | 1353 | if (jamospecial) { |
michael@0 | 1354 | /* gets the max expansion in all unicode characters */ |
michael@0 | 1355 | int count = maxjamoexpansion->position; |
michael@0 | 1356 | uint8_t maxTSize = (uint8_t)(maxjamoexpansion->maxLSize + |
michael@0 | 1357 | maxjamoexpansion->maxVSize + |
michael@0 | 1358 | maxjamoexpansion->maxTSize); |
michael@0 | 1359 | uint8_t maxVSize = (uint8_t)(maxjamoexpansion->maxLSize + |
michael@0 | 1360 | maxjamoexpansion->maxVSize); |
michael@0 | 1361 | |
michael@0 | 1362 | while (count > 0) { |
michael@0 | 1363 | count --; |
michael@0 | 1364 | if (*(maxjamoexpansion->isV + count) == TRUE) { |
michael@0 | 1365 | uprv_uca_setMaxExpansion( |
michael@0 | 1366 | *(maxjamoexpansion->endExpansionCE + count), |
michael@0 | 1367 | maxVSize, maxexpansion, status); |
michael@0 | 1368 | } |
michael@0 | 1369 | else { |
michael@0 | 1370 | uprv_uca_setMaxExpansion( |
michael@0 | 1371 | *(maxjamoexpansion->endExpansionCE + count), |
michael@0 | 1372 | maxTSize, maxexpansion, status); |
michael@0 | 1373 | } |
michael@0 | 1374 | } |
michael@0 | 1375 | } |
michael@0 | 1376 | } |
michael@0 | 1377 | |
michael@0 | 1378 | U_CDECL_BEGIN |
michael@0 | 1379 | static inline uint32_t U_CALLCONV |
michael@0 | 1380 | getFoldedValue(UNewTrie *trie, UChar32 start, int32_t offset) |
michael@0 | 1381 | { |
michael@0 | 1382 | uint32_t value; |
michael@0 | 1383 | uint32_t tag; |
michael@0 | 1384 | UChar32 limit; |
michael@0 | 1385 | UBool inBlockZero; |
michael@0 | 1386 | |
michael@0 | 1387 | limit=start+0x400; |
michael@0 | 1388 | while(start<limit) { |
michael@0 | 1389 | value=utrie_get32(trie, start, &inBlockZero); |
michael@0 | 1390 | tag = getCETag(value); |
michael@0 | 1391 | if(inBlockZero == TRUE) { |
michael@0 | 1392 | start+=UTRIE_DATA_BLOCK_LENGTH; |
michael@0 | 1393 | } else if(!(isSpecial(value) && (tag == IMPLICIT_TAG || tag == NOT_FOUND_TAG))) { |
michael@0 | 1394 | /* These are values that are starting in either UCA (IMPLICIT_TAG) or in the |
michael@0 | 1395 | * tailorings (NOT_FOUND_TAG). Presence of these tags means that there is |
michael@0 | 1396 | * nothing in this position and that it should be skipped. |
michael@0 | 1397 | */ |
michael@0 | 1398 | #ifdef UCOL_DEBUG |
michael@0 | 1399 | static int32_t count = 1; |
michael@0 | 1400 | fprintf(stdout, "%i, Folded %08X, value %08X\n", count++, start, value); |
michael@0 | 1401 | #endif |
michael@0 | 1402 | return (uint32_t)(UCOL_SPECIAL_FLAG | (SURROGATE_TAG<<24) | offset); |
michael@0 | 1403 | } else { |
michael@0 | 1404 | ++start; |
michael@0 | 1405 | } |
michael@0 | 1406 | } |
michael@0 | 1407 | return 0; |
michael@0 | 1408 | } |
michael@0 | 1409 | U_CDECL_END |
michael@0 | 1410 | |
michael@0 | 1411 | #ifdef UCOL_DEBUG |
michael@0 | 1412 | // This is a debug function to print the contents of a trie. |
michael@0 | 1413 | // It is used in conjuction with the code around utrie_unserialize call |
michael@0 | 1414 | UBool enumRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) { |
michael@0 | 1415 | if(start<0x10000) { |
michael@0 | 1416 | fprintf(stdout, "%08X, %08X, %08X\n", start, limit, value); |
michael@0 | 1417 | } else { |
michael@0 | 1418 | fprintf(stdout, "%08X=%04X %04X, %08X=%04X %04X, %08X\n", start, U16_LEAD(start), U16_TRAIL(start), limit, U16_LEAD(limit), U16_TRAIL(limit), value); |
michael@0 | 1419 | } |
michael@0 | 1420 | return TRUE; |
michael@0 | 1421 | } |
michael@0 | 1422 | |
michael@0 | 1423 | int32_t |
michael@0 | 1424 | myGetFoldingOffset(uint32_t data) { |
michael@0 | 1425 | if(data > UCOL_NOT_FOUND && getCETag(data) == SURROGATE_TAG) { |
michael@0 | 1426 | return (data&0xFFFFFF); |
michael@0 | 1427 | } else { |
michael@0 | 1428 | return 0; |
michael@0 | 1429 | } |
michael@0 | 1430 | } |
michael@0 | 1431 | #endif |
michael@0 | 1432 | |
michael@0 | 1433 | U_CAPI UCATableHeader* U_EXPORT2 |
michael@0 | 1434 | uprv_uca_assembleTable(tempUCATable *t, UErrorCode *status) { |
michael@0 | 1435 | /*CompactEIntArray *mapping = t->mapping;*/ |
michael@0 | 1436 | UNewTrie *mapping = t->mapping; |
michael@0 | 1437 | ExpansionTable *expansions = t->expansions; |
michael@0 | 1438 | CntTable *contractions = t->contractions; |
michael@0 | 1439 | MaxExpansionTable *maxexpansion = t->maxExpansions; |
michael@0 | 1440 | |
michael@0 | 1441 | if(U_FAILURE(*status)) { |
michael@0 | 1442 | return NULL; |
michael@0 | 1443 | } |
michael@0 | 1444 | |
michael@0 | 1445 | uint32_t beforeContractions = (uint32_t)((headersize+paddedsize(expansions->position*sizeof(uint32_t)))/sizeof(UChar)); |
michael@0 | 1446 | |
michael@0 | 1447 | int32_t contractionsSize = 0; |
michael@0 | 1448 | contractionsSize = uprv_cnttab_constructTable(contractions, beforeContractions, status); |
michael@0 | 1449 | |
michael@0 | 1450 | /* the following operation depends on the trie data. Therefore, we have to do it before */ |
michael@0 | 1451 | /* the trie is compacted */ |
michael@0 | 1452 | /* sets jamo expansions */ |
michael@0 | 1453 | uprv_uca_getMaxExpansionJamo(mapping, maxexpansion, t->maxJamoExpansions, |
michael@0 | 1454 | t->image->jamoSpecial, status); |
michael@0 | 1455 | |
michael@0 | 1456 | /*ucmpe32_compact(mapping);*/ |
michael@0 | 1457 | /*UMemoryStream *ms = uprv_mstrm_openNew(8192);*/ |
michael@0 | 1458 | /*int32_t mappingSize = ucmpe32_flattenMem(mapping, ms);*/ |
michael@0 | 1459 | /*const uint8_t *flattened = uprv_mstrm_getBuffer(ms, &mappingSize);*/ |
michael@0 | 1460 | |
michael@0 | 1461 | // After setting the jamo expansions, compact the trie and get the needed size |
michael@0 | 1462 | int32_t mappingSize = utrie_serialize(mapping, NULL, 0, getFoldedValue /*getFoldedValue*/, FALSE, status); |
michael@0 | 1463 | |
michael@0 | 1464 | uint32_t tableOffset = 0; |
michael@0 | 1465 | uint8_t *dataStart; |
michael@0 | 1466 | |
michael@0 | 1467 | /* TODO: LATIN1 array is now in the utrie - it should be removed from the calculation */ |
michael@0 | 1468 | |
michael@0 | 1469 | uint32_t toAllocate =(uint32_t)(headersize+ |
michael@0 | 1470 | paddedsize(expansions->position*sizeof(uint32_t))+ |
michael@0 | 1471 | paddedsize(mappingSize)+ |
michael@0 | 1472 | paddedsize(contractionsSize*(sizeof(UChar)+sizeof(uint32_t)))+ |
michael@0 | 1473 | //paddedsize(0x100*sizeof(uint32_t)) /* Latin1 is now included in the trie */ |
michael@0 | 1474 | /* maxexpansion array */ |
michael@0 | 1475 | + paddedsize(maxexpansion->position * sizeof(uint32_t)) + |
michael@0 | 1476 | /* maxexpansion size array */ |
michael@0 | 1477 | paddedsize(maxexpansion->position * sizeof(uint8_t)) + |
michael@0 | 1478 | paddedsize(UCOL_UNSAFECP_TABLE_SIZE) + /* Unsafe chars */ |
michael@0 | 1479 | paddedsize(UCOL_UNSAFECP_TABLE_SIZE)); /* Contraction Ending chars */ |
michael@0 | 1480 | |
michael@0 | 1481 | |
michael@0 | 1482 | dataStart = (uint8_t *)uprv_malloc(toAllocate); |
michael@0 | 1483 | /* test for NULL */ |
michael@0 | 1484 | if (dataStart == NULL) { |
michael@0 | 1485 | *status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 1486 | return NULL; |
michael@0 | 1487 | } |
michael@0 | 1488 | |
michael@0 | 1489 | UCATableHeader *myData = (UCATableHeader *)dataStart; |
michael@0 | 1490 | // Please, do reset all the fields! |
michael@0 | 1491 | uprv_memset(dataStart, 0, toAllocate); |
michael@0 | 1492 | // Make sure we know this is reset |
michael@0 | 1493 | myData->magic = UCOL_HEADER_MAGIC; |
michael@0 | 1494 | myData->isBigEndian = U_IS_BIG_ENDIAN; |
michael@0 | 1495 | myData->charSetFamily = U_CHARSET_FAMILY; |
michael@0 | 1496 | myData->formatVersion[0] = UCA_FORMAT_VERSION_0; |
michael@0 | 1497 | myData->formatVersion[1] = UCA_FORMAT_VERSION_1; |
michael@0 | 1498 | myData->formatVersion[2] = UCA_FORMAT_VERSION_2; |
michael@0 | 1499 | myData->formatVersion[3] = UCA_FORMAT_VERSION_3; |
michael@0 | 1500 | myData->jamoSpecial = t->image->jamoSpecial; |
michael@0 | 1501 | |
michael@0 | 1502 | // Don't copy stuff from UCA header! |
michael@0 | 1503 | //uprv_memcpy(myData, t->image, sizeof(UCATableHeader)); |
michael@0 | 1504 | |
michael@0 | 1505 | myData->contractionSize = contractionsSize; |
michael@0 | 1506 | |
michael@0 | 1507 | tableOffset += (uint32_t)(paddedsize(sizeof(UCATableHeader))); |
michael@0 | 1508 | |
michael@0 | 1509 | myData->options = tableOffset; |
michael@0 | 1510 | uprv_memcpy(dataStart+tableOffset, t->options, sizeof(UColOptionSet)); |
michael@0 | 1511 | tableOffset += (uint32_t)(paddedsize(sizeof(UColOptionSet))); |
michael@0 | 1512 | |
michael@0 | 1513 | /* copy expansions */ |
michael@0 | 1514 | /*myData->expansion = (uint32_t *)dataStart+tableOffset;*/ |
michael@0 | 1515 | myData->expansion = tableOffset; |
michael@0 | 1516 | uprv_memcpy(dataStart+tableOffset, expansions->CEs, expansions->position*sizeof(uint32_t)); |
michael@0 | 1517 | tableOffset += (uint32_t)(paddedsize(expansions->position*sizeof(uint32_t))); |
michael@0 | 1518 | |
michael@0 | 1519 | /* contractions block */ |
michael@0 | 1520 | if(contractionsSize != 0) { |
michael@0 | 1521 | /* copy contraction index */ |
michael@0 | 1522 | /*myData->contractionIndex = (UChar *)(dataStart+tableOffset);*/ |
michael@0 | 1523 | myData->contractionIndex = tableOffset; |
michael@0 | 1524 | uprv_memcpy(dataStart+tableOffset, contractions->codePoints, contractionsSize*sizeof(UChar)); |
michael@0 | 1525 | tableOffset += (uint32_t)(paddedsize(contractionsSize*sizeof(UChar))); |
michael@0 | 1526 | |
michael@0 | 1527 | /* copy contraction collation elements */ |
michael@0 | 1528 | /*myData->contractionCEs = (uint32_t *)(dataStart+tableOffset);*/ |
michael@0 | 1529 | myData->contractionCEs = tableOffset; |
michael@0 | 1530 | uprv_memcpy(dataStart+tableOffset, contractions->CEs, contractionsSize*sizeof(uint32_t)); |
michael@0 | 1531 | tableOffset += (uint32_t)(paddedsize(contractionsSize*sizeof(uint32_t))); |
michael@0 | 1532 | } else { |
michael@0 | 1533 | myData->contractionIndex = 0; |
michael@0 | 1534 | myData->contractionCEs = 0; |
michael@0 | 1535 | } |
michael@0 | 1536 | |
michael@0 | 1537 | /* copy mapping table */ |
michael@0 | 1538 | /*myData->mappingPosition = dataStart+tableOffset;*/ |
michael@0 | 1539 | /*myData->mappingPosition = tableOffset;*/ |
michael@0 | 1540 | /*uprv_memcpy(dataStart+tableOffset, flattened, mappingSize);*/ |
michael@0 | 1541 | |
michael@0 | 1542 | myData->mappingPosition = tableOffset; |
michael@0 | 1543 | utrie_serialize(mapping, dataStart+tableOffset, toAllocate-tableOffset, getFoldedValue, FALSE, status); |
michael@0 | 1544 | #ifdef UCOL_DEBUG |
michael@0 | 1545 | // This is debug code to dump the contents of the trie. It needs two functions defined above |
michael@0 | 1546 | { |
michael@0 | 1547 | UTrie UCAt = { 0 }; |
michael@0 | 1548 | uint32_t trieWord; |
michael@0 | 1549 | utrie_unserialize(&UCAt, dataStart+tableOffset, 9999999, status); |
michael@0 | 1550 | UCAt.getFoldingOffset = myGetFoldingOffset; |
michael@0 | 1551 | if(U_SUCCESS(*status)) { |
michael@0 | 1552 | utrie_enum(&UCAt, NULL, enumRange, NULL); |
michael@0 | 1553 | } |
michael@0 | 1554 | trieWord = UTRIE_GET32_FROM_LEAD(&UCAt, 0xDC01); |
michael@0 | 1555 | } |
michael@0 | 1556 | #endif |
michael@0 | 1557 | tableOffset += paddedsize(mappingSize); |
michael@0 | 1558 | |
michael@0 | 1559 | |
michael@0 | 1560 | int32_t i = 0; |
michael@0 | 1561 | |
michael@0 | 1562 | /* copy max expansion table */ |
michael@0 | 1563 | myData->endExpansionCE = tableOffset; |
michael@0 | 1564 | myData->endExpansionCECount = maxexpansion->position - 1; |
michael@0 | 1565 | /* not copying the first element which is a dummy */ |
michael@0 | 1566 | uprv_memcpy(dataStart + tableOffset, maxexpansion->endExpansionCE + 1, |
michael@0 | 1567 | (maxexpansion->position - 1) * sizeof(uint32_t)); |
michael@0 | 1568 | tableOffset += (uint32_t)(paddedsize((maxexpansion->position)* sizeof(uint32_t))); |
michael@0 | 1569 | myData->expansionCESize = tableOffset; |
michael@0 | 1570 | uprv_memcpy(dataStart + tableOffset, maxexpansion->expansionCESize + 1, |
michael@0 | 1571 | (maxexpansion->position - 1) * sizeof(uint8_t)); |
michael@0 | 1572 | tableOffset += (uint32_t)(paddedsize((maxexpansion->position)* sizeof(uint8_t))); |
michael@0 | 1573 | |
michael@0 | 1574 | /* Unsafe chars table. Finish it off, then copy it. */ |
michael@0 | 1575 | uprv_uca_unsafeCPAddCCNZ(t, status); |
michael@0 | 1576 | if (t->UCA != 0) { /* Or in unsafebits from UCA, making a combined table. */ |
michael@0 | 1577 | for (i=0; i<UCOL_UNSAFECP_TABLE_SIZE; i++) { |
michael@0 | 1578 | t->unsafeCP[i] |= t->UCA->unsafeCP[i]; |
michael@0 | 1579 | } |
michael@0 | 1580 | } |
michael@0 | 1581 | myData->unsafeCP = tableOffset; |
michael@0 | 1582 | uprv_memcpy(dataStart + tableOffset, t->unsafeCP, UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 1583 | tableOffset += paddedsize(UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 1584 | |
michael@0 | 1585 | |
michael@0 | 1586 | /* Finish building Contraction Ending chars hash table and then copy it out. */ |
michael@0 | 1587 | if (t->UCA != 0) { /* Or in unsafebits from UCA, making a combined table. */ |
michael@0 | 1588 | for (i=0; i<UCOL_UNSAFECP_TABLE_SIZE; i++) { |
michael@0 | 1589 | t->contrEndCP[i] |= t->UCA->contrEndCP[i]; |
michael@0 | 1590 | } |
michael@0 | 1591 | } |
michael@0 | 1592 | myData->contrEndCP = tableOffset; |
michael@0 | 1593 | uprv_memcpy(dataStart + tableOffset, t->contrEndCP, UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 1594 | tableOffset += paddedsize(UCOL_UNSAFECP_TABLE_SIZE); |
michael@0 | 1595 | |
michael@0 | 1596 | if(tableOffset != toAllocate) { |
michael@0 | 1597 | #ifdef UCOL_DEBUG |
michael@0 | 1598 | fprintf(stderr, "calculation screwup!!! Expected to write %i but wrote %i instead!!!\n", toAllocate, tableOffset); |
michael@0 | 1599 | #endif |
michael@0 | 1600 | *status = U_INTERNAL_PROGRAM_ERROR; |
michael@0 | 1601 | uprv_free(dataStart); |
michael@0 | 1602 | return 0; |
michael@0 | 1603 | } |
michael@0 | 1604 | |
michael@0 | 1605 | myData->size = tableOffset; |
michael@0 | 1606 | /* This should happen upon ressurection */ |
michael@0 | 1607 | /*const uint8_t *mapPosition = (uint8_t*)myData+myData->mappingPosition;*/ |
michael@0 | 1608 | /*uprv_mstrm_close(ms);*/ |
michael@0 | 1609 | return myData; |
michael@0 | 1610 | } |
michael@0 | 1611 | |
michael@0 | 1612 | |
michael@0 | 1613 | struct enumStruct { |
michael@0 | 1614 | tempUCATable *t; |
michael@0 | 1615 | UCollator *tempColl; |
michael@0 | 1616 | UCollationElements* colEl; |
michael@0 | 1617 | const Normalizer2Impl *nfcImpl; |
michael@0 | 1618 | UnicodeSet *closed; |
michael@0 | 1619 | int32_t noOfClosures; |
michael@0 | 1620 | UErrorCode *status; |
michael@0 | 1621 | }; |
michael@0 | 1622 | U_CDECL_BEGIN |
michael@0 | 1623 | static UBool U_CALLCONV |
michael@0 | 1624 | _enumCategoryRangeClosureCategory(const void *context, UChar32 start, UChar32 limit, UCharCategory type) { |
michael@0 | 1625 | |
michael@0 | 1626 | if (type != U_UNASSIGNED && type != U_PRIVATE_USE_CHAR) { // if the range is assigned - we might ommit more categories later |
michael@0 | 1627 | UErrorCode *status = ((enumStruct *)context)->status; |
michael@0 | 1628 | tempUCATable *t = ((enumStruct *)context)->t; |
michael@0 | 1629 | UCollator *tempColl = ((enumStruct *)context)->tempColl; |
michael@0 | 1630 | UCollationElements* colEl = ((enumStruct *)context)->colEl; |
michael@0 | 1631 | UCAElements el; |
michael@0 | 1632 | UChar decompBuffer[4]; |
michael@0 | 1633 | const UChar *decomp; |
michael@0 | 1634 | int32_t noOfDec = 0; |
michael@0 | 1635 | |
michael@0 | 1636 | UChar32 u32 = 0; |
michael@0 | 1637 | UChar comp[2]; |
michael@0 | 1638 | uint32_t len = 0; |
michael@0 | 1639 | |
michael@0 | 1640 | for(u32 = start; u32 < limit; u32++) { |
michael@0 | 1641 | decomp = ((enumStruct *)context)->nfcImpl-> |
michael@0 | 1642 | getDecomposition(u32, decompBuffer, noOfDec); |
michael@0 | 1643 | //if((noOfDec = unorm_normalize(comp, len, UNORM_NFD, 0, decomp, 256, status)) > 1 |
michael@0 | 1644 | //|| (noOfDec == 1 && *decomp != (UChar)u32)) |
michael@0 | 1645 | if(decomp != NULL) |
michael@0 | 1646 | { |
michael@0 | 1647 | len = 0; |
michael@0 | 1648 | U16_APPEND_UNSAFE(comp, len, u32); |
michael@0 | 1649 | if(ucol_strcoll(tempColl, comp, len, decomp, noOfDec) != UCOL_EQUAL) { |
michael@0 | 1650 | #ifdef UCOL_DEBUG |
michael@0 | 1651 | fprintf(stderr, "Closure: U+%04X -> ", u32); |
michael@0 | 1652 | UChar32 c; |
michael@0 | 1653 | int32_t i = 0; |
michael@0 | 1654 | while(i < noOfDec) { |
michael@0 | 1655 | U16_NEXT(decomp, i, noOfDec, c); |
michael@0 | 1656 | fprintf(stderr, "%04X ", c); |
michael@0 | 1657 | } |
michael@0 | 1658 | fprintf(stderr, "\n"); |
michael@0 | 1659 | // print CEs for code point vs. decomposition |
michael@0 | 1660 | fprintf(stderr, "U+%04X CEs: ", u32); |
michael@0 | 1661 | UCollationElements *iter = ucol_openElements(tempColl, comp, len, status); |
michael@0 | 1662 | int32_t ce; |
michael@0 | 1663 | while((ce = ucol_next(iter, status)) != UCOL_NULLORDER) { |
michael@0 | 1664 | fprintf(stderr, "%08X ", ce); |
michael@0 | 1665 | } |
michael@0 | 1666 | fprintf(stderr, "\nDecomp CEs: "); |
michael@0 | 1667 | ucol_setText(iter, decomp, noOfDec, status); |
michael@0 | 1668 | while((ce = ucol_next(iter, status)) != UCOL_NULLORDER) { |
michael@0 | 1669 | fprintf(stderr, "%08X ", ce); |
michael@0 | 1670 | } |
michael@0 | 1671 | fprintf(stderr, "\n"); |
michael@0 | 1672 | ucol_closeElements(iter); |
michael@0 | 1673 | #endif |
michael@0 | 1674 | if(((enumStruct *)context)->closed != NULL) { |
michael@0 | 1675 | ((enumStruct *)context)->closed->add(u32); |
michael@0 | 1676 | } |
michael@0 | 1677 | ((enumStruct *)context)->noOfClosures++; |
michael@0 | 1678 | el.cPoints = (UChar *)decomp; |
michael@0 | 1679 | el.cSize = noOfDec; |
michael@0 | 1680 | el.noOfCEs = 0; |
michael@0 | 1681 | el.prefix = el.prefixChars; |
michael@0 | 1682 | el.prefixSize = 0; |
michael@0 | 1683 | |
michael@0 | 1684 | UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, &el); |
michael@0 | 1685 | el.cPoints = comp; |
michael@0 | 1686 | el.cSize = len; |
michael@0 | 1687 | el.prefix = el.prefixChars; |
michael@0 | 1688 | el.prefixSize = 0; |
michael@0 | 1689 | if(prefix == NULL) { |
michael@0 | 1690 | el.noOfCEs = 0; |
michael@0 | 1691 | ucol_setText(colEl, decomp, noOfDec, status); |
michael@0 | 1692 | while((el.CEs[el.noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) { |
michael@0 | 1693 | el.noOfCEs++; |
michael@0 | 1694 | } |
michael@0 | 1695 | } else { |
michael@0 | 1696 | el.noOfCEs = 1; |
michael@0 | 1697 | el.CEs[0] = prefix->mapCE; |
michael@0 | 1698 | // This character uses a prefix. We have to add it |
michael@0 | 1699 | // to the unsafe table, as it decomposed form is already |
michael@0 | 1700 | // in. In Japanese, this happens for \u309e & \u30fe |
michael@0 | 1701 | // Since unsafeCPSet is static in ucol_elm, we are going |
michael@0 | 1702 | // to wrap it up in the uprv_uca_unsafeCPAddCCNZ function |
michael@0 | 1703 | } |
michael@0 | 1704 | uprv_uca_addAnElement(t, &el, status); |
michael@0 | 1705 | } |
michael@0 | 1706 | } |
michael@0 | 1707 | } |
michael@0 | 1708 | } |
michael@0 | 1709 | return TRUE; |
michael@0 | 1710 | } |
michael@0 | 1711 | U_CDECL_END |
michael@0 | 1712 | |
michael@0 | 1713 | static void |
michael@0 | 1714 | uprv_uca_setMapCE(tempUCATable *t, UCAElements *element, UErrorCode *status) { |
michael@0 | 1715 | uint32_t expansion = 0; |
michael@0 | 1716 | int32_t j; |
michael@0 | 1717 | |
michael@0 | 1718 | ExpansionTable *expansions = t->expansions; |
michael@0 | 1719 | if(element->noOfCEs == 2 // a two CE expansion |
michael@0 | 1720 | && isContinuation(element->CEs[1]) // which is a continuation |
michael@0 | 1721 | && (element->CEs[1] & (~(0xFF << 24 | UCOL_CONTINUATION_MARKER))) == 0 // that has only primaries in continuation, |
michael@0 | 1722 | && (((element->CEs[0]>>8) & 0xFF) == UCOL_BYTE_COMMON) // a common secondary |
michael@0 | 1723 | && ((element->CEs[0] & 0xFF) == UCOL_BYTE_COMMON) // and a common tertiary |
michael@0 | 1724 | ) { |
michael@0 | 1725 | element->mapCE = UCOL_SPECIAL_FLAG | (LONG_PRIMARY_TAG<<24) // a long primary special |
michael@0 | 1726 | | ((element->CEs[0]>>8) & 0xFFFF00) // first and second byte of primary |
michael@0 | 1727 | | ((element->CEs[1]>>24) & 0xFF); // third byte of primary |
michael@0 | 1728 | } else { |
michael@0 | 1729 | expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (EXPANSION_TAG<<UCOL_TAG_SHIFT) |
michael@0 | 1730 | | (((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4) |
michael@0 | 1731 | & 0xFFFFF0)); |
michael@0 | 1732 | |
michael@0 | 1733 | for(j = 1; j<(int32_t)element->noOfCEs; j++) { |
michael@0 | 1734 | uprv_uca_addExpansion(expansions, element->CEs[j], status); |
michael@0 | 1735 | } |
michael@0 | 1736 | if(element->noOfCEs <= 0xF) { |
michael@0 | 1737 | expansion |= element->noOfCEs; |
michael@0 | 1738 | } else { |
michael@0 | 1739 | uprv_uca_addExpansion(expansions, 0, status); |
michael@0 | 1740 | } |
michael@0 | 1741 | element->mapCE = expansion; |
michael@0 | 1742 | uprv_uca_setMaxExpansion(element->CEs[element->noOfCEs - 1], |
michael@0 | 1743 | (uint8_t)element->noOfCEs, |
michael@0 | 1744 | t->maxExpansions, |
michael@0 | 1745 | status); |
michael@0 | 1746 | } |
michael@0 | 1747 | } |
michael@0 | 1748 | |
michael@0 | 1749 | static void |
michael@0 | 1750 | uprv_uca_addFCD4AccentedContractions(tempUCATable *t, |
michael@0 | 1751 | UCollationElements* colEl, |
michael@0 | 1752 | UChar *data, |
michael@0 | 1753 | int32_t len, |
michael@0 | 1754 | UCAElements *el, |
michael@0 | 1755 | UErrorCode *status) { |
michael@0 | 1756 | UChar decomp[256], comp[256]; |
michael@0 | 1757 | int32_t decLen, compLen; |
michael@0 | 1758 | |
michael@0 | 1759 | decLen = unorm_normalize(data, len, UNORM_NFD, 0, decomp, 256, status); |
michael@0 | 1760 | compLen = unorm_normalize(data, len, UNORM_NFC, 0, comp, 256, status); |
michael@0 | 1761 | decomp[decLen] = comp[compLen] = 0; |
michael@0 | 1762 | |
michael@0 | 1763 | el->cPoints = decomp; |
michael@0 | 1764 | el->cSize = decLen; |
michael@0 | 1765 | el->noOfCEs = 0; |
michael@0 | 1766 | el->prefixSize = 0; |
michael@0 | 1767 | el->prefix = el->prefixChars; |
michael@0 | 1768 | |
michael@0 | 1769 | UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, el); |
michael@0 | 1770 | el->cPoints = comp; |
michael@0 | 1771 | el->cSize = compLen; |
michael@0 | 1772 | el->prefix = el->prefixChars; |
michael@0 | 1773 | el->prefixSize = 0; |
michael@0 | 1774 | if(prefix == NULL) { |
michael@0 | 1775 | el->noOfCEs = 0; |
michael@0 | 1776 | ucol_setText(colEl, decomp, decLen, status); |
michael@0 | 1777 | while((el->CEs[el->noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) { |
michael@0 | 1778 | el->noOfCEs++; |
michael@0 | 1779 | } |
michael@0 | 1780 | uprv_uca_setMapCE(t, el, status); |
michael@0 | 1781 | uprv_uca_addAnElement(t, el, status); |
michael@0 | 1782 | } |
michael@0 | 1783 | el->cPoints=NULL; /* don't leak reference to stack */ |
michael@0 | 1784 | } |
michael@0 | 1785 | |
michael@0 | 1786 | static void |
michael@0 | 1787 | uprv_uca_addMultiCMContractions(tempUCATable *t, |
michael@0 | 1788 | UCollationElements* colEl, |
michael@0 | 1789 | tempTailorContext *c, |
michael@0 | 1790 | UCAElements *el, |
michael@0 | 1791 | UErrorCode *status) { |
michael@0 | 1792 | CombinClassTable *cmLookup = t->cmLookup; |
michael@0 | 1793 | UChar newDecomp[256]; |
michael@0 | 1794 | int32_t maxComp, newDecLen; |
michael@0 | 1795 | const Normalizer2Impl *nfcImpl = Normalizer2Factory::getNFCImpl(*status); |
michael@0 | 1796 | if (U_FAILURE(*status)) { |
michael@0 | 1797 | return; |
michael@0 | 1798 | } |
michael@0 | 1799 | int16_t curClass = nfcImpl->getFCD16(c->tailoringCM) & 0xff; |
michael@0 | 1800 | CompData *precomp = c->precomp; |
michael@0 | 1801 | int32_t compLen = c->compLen; |
michael@0 | 1802 | UChar *comp = c->comp; |
michael@0 | 1803 | maxComp = c->precompLen; |
michael@0 | 1804 | |
michael@0 | 1805 | for (int32_t j=0; j < maxComp; j++) { |
michael@0 | 1806 | int32_t count=0; |
michael@0 | 1807 | do { |
michael@0 | 1808 | if ( count == 0 ) { // Decompose the saved precomposed char. |
michael@0 | 1809 | UChar temp[2]; |
michael@0 | 1810 | temp[0]=precomp[j].cp; |
michael@0 | 1811 | temp[1]=0; |
michael@0 | 1812 | newDecLen = unorm_normalize(temp, 1, UNORM_NFD, 0, |
michael@0 | 1813 | newDecomp, sizeof(newDecomp)/sizeof(UChar), status); |
michael@0 | 1814 | newDecomp[newDecLen++] = cmLookup->cPoints[c->cmPos]; |
michael@0 | 1815 | } |
michael@0 | 1816 | else { // swap 2 combining marks when they are equal. |
michael@0 | 1817 | uprv_memcpy(newDecomp, c->decomp, sizeof(UChar)*(c->decompLen)); |
michael@0 | 1818 | newDecLen = c->decompLen; |
michael@0 | 1819 | newDecomp[newDecLen++] = precomp[j].cClass; |
michael@0 | 1820 | } |
michael@0 | 1821 | newDecomp[newDecLen] = 0; |
michael@0 | 1822 | compLen = unorm_normalize(newDecomp, newDecLen, UNORM_NFC, 0, |
michael@0 | 1823 | comp, 256, status); |
michael@0 | 1824 | if (compLen==1) { |
michael@0 | 1825 | comp[compLen++] = newDecomp[newDecLen++] = c->tailoringCM; |
michael@0 | 1826 | comp[compLen] = newDecomp[newDecLen] = 0; |
michael@0 | 1827 | el->cPoints = newDecomp; |
michael@0 | 1828 | el->cSize = newDecLen; |
michael@0 | 1829 | |
michael@0 | 1830 | UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, el); |
michael@0 | 1831 | el->cPoints = c->comp; |
michael@0 | 1832 | el->cSize = compLen; |
michael@0 | 1833 | el->prefix = el->prefixChars; |
michael@0 | 1834 | el->prefixSize = 0; |
michael@0 | 1835 | if(prefix == NULL) { |
michael@0 | 1836 | el->noOfCEs = 0; |
michael@0 | 1837 | ucol_setText(colEl, newDecomp, newDecLen, status); |
michael@0 | 1838 | while((el->CEs[el->noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) { |
michael@0 | 1839 | el->noOfCEs++; |
michael@0 | 1840 | } |
michael@0 | 1841 | uprv_uca_setMapCE(t, el, status); |
michael@0 | 1842 | uprv_uca_finalizeAddition(t, el, status); |
michael@0 | 1843 | |
michael@0 | 1844 | // Save the current precomposed char and its class to find any |
michael@0 | 1845 | // other combining mark combinations. |
michael@0 | 1846 | precomp[c->precompLen].cp=comp[0]; |
michael@0 | 1847 | precomp[c->precompLen].cClass = curClass; |
michael@0 | 1848 | c->precompLen++; |
michael@0 | 1849 | } |
michael@0 | 1850 | } |
michael@0 | 1851 | } while (++count<2 && (precomp[j].cClass == curClass)); |
michael@0 | 1852 | } |
michael@0 | 1853 | |
michael@0 | 1854 | } |
michael@0 | 1855 | |
michael@0 | 1856 | static void |
michael@0 | 1857 | uprv_uca_addTailCanonicalClosures(tempUCATable *t, |
michael@0 | 1858 | UCollationElements* colEl, |
michael@0 | 1859 | UChar baseCh, |
michael@0 | 1860 | UChar cMark, |
michael@0 | 1861 | UCAElements *el, |
michael@0 | 1862 | UErrorCode *status) { |
michael@0 | 1863 | CombinClassTable *cmLookup = t->cmLookup; |
michael@0 | 1864 | const Normalizer2Impl *nfcImpl = Normalizer2Factory::getNFCImpl(*status); |
michael@0 | 1865 | if (U_FAILURE(*status)) { |
michael@0 | 1866 | return; |
michael@0 | 1867 | } |
michael@0 | 1868 | int16_t maxIndex = nfcImpl->getFCD16(cMark) & 0xff; |
michael@0 | 1869 | UCAElements element; |
michael@0 | 1870 | uint16_t *index; |
michael@0 | 1871 | UChar decomp[256]; |
michael@0 | 1872 | UChar comp[256]; |
michael@0 | 1873 | CompData precomp[256]; // precomposed array |
michael@0 | 1874 | int32_t precompLen = 0; // count for precomp |
michael@0 | 1875 | int32_t i, len, decompLen, replacedPos; |
michael@0 | 1876 | tempTailorContext c; |
michael@0 | 1877 | |
michael@0 | 1878 | if ( cmLookup == NULL ) { |
michael@0 | 1879 | return; |
michael@0 | 1880 | } |
michael@0 | 1881 | index = cmLookup->index; |
michael@0 | 1882 | int32_t cClass=nfcImpl->getFCD16(cMark) & 0xff; |
michael@0 | 1883 | maxIndex = (int32_t)index[(nfcImpl->getFCD16(cMark) & 0xff)-1]; |
michael@0 | 1884 | c.comp = comp; |
michael@0 | 1885 | c.decomp = decomp; |
michael@0 | 1886 | c.precomp = precomp; |
michael@0 | 1887 | c.tailoringCM = cMark; |
michael@0 | 1888 | |
michael@0 | 1889 | if (cClass>0) { |
michael@0 | 1890 | maxIndex = (int32_t)index[cClass-1]; |
michael@0 | 1891 | } |
michael@0 | 1892 | else { |
michael@0 | 1893 | maxIndex=0; |
michael@0 | 1894 | } |
michael@0 | 1895 | decomp[0]=baseCh; |
michael@0 | 1896 | for ( i=0; i<maxIndex ; i++ ) { |
michael@0 | 1897 | decomp[1] = cmLookup->cPoints[i]; |
michael@0 | 1898 | decomp[2]=0; |
michael@0 | 1899 | decompLen=2; |
michael@0 | 1900 | len = unorm_normalize(decomp, decompLen, UNORM_NFC, 0, comp, 256, status); |
michael@0 | 1901 | if (len==1) { |
michael@0 | 1902 | // Save the current precomposed char and its class to find any |
michael@0 | 1903 | // other combining mark combinations. |
michael@0 | 1904 | precomp[precompLen].cp=comp[0]; |
michael@0 | 1905 | precomp[precompLen].cClass = |
michael@0 | 1906 | index[nfcImpl->getFCD16(decomp[1]) & 0xff]; |
michael@0 | 1907 | precompLen++; |
michael@0 | 1908 | replacedPos=0; |
michael@0 | 1909 | for (decompLen=0; decompLen< (int32_t)el->cSize; decompLen++) { |
michael@0 | 1910 | decomp[decompLen] = el->cPoints[decompLen]; |
michael@0 | 1911 | if (decomp[decompLen]==cMark) { |
michael@0 | 1912 | replacedPos = decompLen; // record the position for later use |
michael@0 | 1913 | } |
michael@0 | 1914 | } |
michael@0 | 1915 | if ( replacedPos != 0 ) { |
michael@0 | 1916 | decomp[replacedPos]=cmLookup->cPoints[i]; |
michael@0 | 1917 | } |
michael@0 | 1918 | decomp[decompLen] = 0; |
michael@0 | 1919 | len = unorm_normalize(decomp, decompLen, UNORM_NFC, 0, comp, 256, status); |
michael@0 | 1920 | comp[len++] = decomp[decompLen++] = cMark; |
michael@0 | 1921 | comp[len] = decomp[decompLen] = 0; |
michael@0 | 1922 | element.cPoints = decomp; |
michael@0 | 1923 | element.cSize = decompLen; |
michael@0 | 1924 | element.noOfCEs = 0; |
michael@0 | 1925 | element.prefix = el->prefixChars; |
michael@0 | 1926 | element.prefixSize = 0; |
michael@0 | 1927 | |
michael@0 | 1928 | UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, &element); |
michael@0 | 1929 | element.cPoints = comp; |
michael@0 | 1930 | element.cSize = len; |
michael@0 | 1931 | element.prefix = el->prefixChars; |
michael@0 | 1932 | element.prefixSize = 0; |
michael@0 | 1933 | if(prefix == NULL) { |
michael@0 | 1934 | element.noOfCEs = 0; |
michael@0 | 1935 | ucol_setText(colEl, decomp, decompLen, status); |
michael@0 | 1936 | while((element.CEs[element.noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) { |
michael@0 | 1937 | element.noOfCEs++; |
michael@0 | 1938 | } |
michael@0 | 1939 | uprv_uca_setMapCE(t, &element, status); |
michael@0 | 1940 | uprv_uca_finalizeAddition(t, &element, status); |
michael@0 | 1941 | } |
michael@0 | 1942 | |
michael@0 | 1943 | // This is a fix for tailoring contractions with accented |
michael@0 | 1944 | // character at the end of contraction string. |
michael@0 | 1945 | if ((len>2) && |
michael@0 | 1946 | (nfcImpl->getFCD16(comp[len-2]) & 0xff00)==0) { |
michael@0 | 1947 | uprv_uca_addFCD4AccentedContractions(t, colEl, comp, len, &element, status); |
michael@0 | 1948 | } |
michael@0 | 1949 | |
michael@0 | 1950 | if (precompLen >1) { |
michael@0 | 1951 | c.compLen = len; |
michael@0 | 1952 | c.decompLen = decompLen; |
michael@0 | 1953 | c.precompLen = precompLen; |
michael@0 | 1954 | c.cmPos = i; |
michael@0 | 1955 | uprv_uca_addMultiCMContractions(t, colEl, &c, &element, status); |
michael@0 | 1956 | precompLen = c.precompLen; |
michael@0 | 1957 | } |
michael@0 | 1958 | } |
michael@0 | 1959 | } |
michael@0 | 1960 | } |
michael@0 | 1961 | |
michael@0 | 1962 | U_CFUNC int32_t U_EXPORT2 |
michael@0 | 1963 | uprv_uca_canonicalClosure(tempUCATable *t, |
michael@0 | 1964 | UColTokenParser *src, |
michael@0 | 1965 | UnicodeSet *closed, |
michael@0 | 1966 | UErrorCode *status) |
michael@0 | 1967 | { |
michael@0 | 1968 | enumStruct context; |
michael@0 | 1969 | context.closed = closed; |
michael@0 | 1970 | context.noOfClosures = 0; |
michael@0 | 1971 | UCAElements el; |
michael@0 | 1972 | UColToken *tok; |
michael@0 | 1973 | uint32_t i = 0, j = 0; |
michael@0 | 1974 | UChar baseChar, firstCM; |
michael@0 | 1975 | context.nfcImpl=Normalizer2Factory::getNFCImpl(*status); |
michael@0 | 1976 | if(U_FAILURE(*status)) { |
michael@0 | 1977 | return 0; |
michael@0 | 1978 | } |
michael@0 | 1979 | |
michael@0 | 1980 | UCollator *tempColl = NULL; |
michael@0 | 1981 | tempUCATable *tempTable = uprv_uca_cloneTempTable(t, status); |
michael@0 | 1982 | // Check for null pointer |
michael@0 | 1983 | if (U_FAILURE(*status)) { |
michael@0 | 1984 | return 0; |
michael@0 | 1985 | } |
michael@0 | 1986 | |
michael@0 | 1987 | UCATableHeader *tempData = uprv_uca_assembleTable(tempTable, status); |
michael@0 | 1988 | tempColl = ucol_initCollator(tempData, 0, t->UCA, status); |
michael@0 | 1989 | if ( tempTable->cmLookup != NULL ) { |
michael@0 | 1990 | t->cmLookup = tempTable->cmLookup; // copy over to t |
michael@0 | 1991 | tempTable->cmLookup = NULL; |
michael@0 | 1992 | } |
michael@0 | 1993 | uprv_uca_closeTempTable(tempTable); |
michael@0 | 1994 | |
michael@0 | 1995 | if(U_SUCCESS(*status)) { |
michael@0 | 1996 | tempColl->ucaRules = NULL; |
michael@0 | 1997 | tempColl->actualLocale = NULL; |
michael@0 | 1998 | tempColl->validLocale = NULL; |
michael@0 | 1999 | tempColl->requestedLocale = NULL; |
michael@0 | 2000 | tempColl->hasRealData = TRUE; |
michael@0 | 2001 | tempColl->freeImageOnClose = TRUE; |
michael@0 | 2002 | } else if(tempData != 0) { |
michael@0 | 2003 | uprv_free(tempData); |
michael@0 | 2004 | } |
michael@0 | 2005 | |
michael@0 | 2006 | /* produce canonical closure */ |
michael@0 | 2007 | UCollationElements* colEl = ucol_openElements(tempColl, NULL, 0, status); |
michael@0 | 2008 | // Check for null pointer |
michael@0 | 2009 | if (U_FAILURE(*status)) { |
michael@0 | 2010 | return 0; |
michael@0 | 2011 | } |
michael@0 | 2012 | context.t = t; |
michael@0 | 2013 | context.tempColl = tempColl; |
michael@0 | 2014 | context.colEl = colEl; |
michael@0 | 2015 | context.status = status; |
michael@0 | 2016 | u_enumCharTypes(_enumCategoryRangeClosureCategory, &context); |
michael@0 | 2017 | |
michael@0 | 2018 | if ( (src==NULL) || !src->buildCCTabFlag ) { |
michael@0 | 2019 | ucol_closeElements(colEl); |
michael@0 | 2020 | ucol_close(tempColl); |
michael@0 | 2021 | return context.noOfClosures; // no extra contraction needed to add |
michael@0 | 2022 | } |
michael@0 | 2023 | |
michael@0 | 2024 | for (i=0; i < src->resultLen; i++) { |
michael@0 | 2025 | baseChar = firstCM= (UChar)0; |
michael@0 | 2026 | tok = src->lh[i].first; |
michael@0 | 2027 | while (tok != NULL && U_SUCCESS(*status)) { |
michael@0 | 2028 | el.prefix = el.prefixChars; |
michael@0 | 2029 | el.cPoints = el.uchars; |
michael@0 | 2030 | if(tok->prefix != 0) { |
michael@0 | 2031 | el.prefixSize = tok->prefix>>24; |
michael@0 | 2032 | uprv_memcpy(el.prefix, src->source + (tok->prefix & 0x00FFFFFF), el.prefixSize*sizeof(UChar)); |
michael@0 | 2033 | |
michael@0 | 2034 | el.cSize = (tok->source >> 24)-(tok->prefix>>24); |
michael@0 | 2035 | uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF)+(tok->prefix>>24) + src->source, el.cSize*sizeof(UChar)); |
michael@0 | 2036 | } else { |
michael@0 | 2037 | el.prefixSize = 0; |
michael@0 | 2038 | *el.prefix = 0; |
michael@0 | 2039 | |
michael@0 | 2040 | el.cSize = (tok->source >> 24); |
michael@0 | 2041 | uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF) + src->source, el.cSize*sizeof(UChar)); |
michael@0 | 2042 | } |
michael@0 | 2043 | if(src->UCA != NULL) { |
michael@0 | 2044 | for(j = 0; j<el.cSize; j++) { |
michael@0 | 2045 | int16_t fcd = context.nfcImpl->getFCD16(el.cPoints[j]); |
michael@0 | 2046 | if ( (fcd & 0xff) == 0 ) { |
michael@0 | 2047 | baseChar = el.cPoints[j]; // last base character |
michael@0 | 2048 | firstCM=0; // reset combining mark value |
michael@0 | 2049 | } |
michael@0 | 2050 | else { |
michael@0 | 2051 | if ( (baseChar!=0) && (firstCM==0) ) { |
michael@0 | 2052 | firstCM = el.cPoints[j]; // first combining mark |
michael@0 | 2053 | } |
michael@0 | 2054 | } |
michael@0 | 2055 | } |
michael@0 | 2056 | } |
michael@0 | 2057 | if ( (baseChar!= (UChar)0) && (firstCM != (UChar)0) ) { |
michael@0 | 2058 | // find all the canonical rules |
michael@0 | 2059 | uprv_uca_addTailCanonicalClosures(t, colEl, baseChar, firstCM, &el, status); |
michael@0 | 2060 | } |
michael@0 | 2061 | tok = tok->next; |
michael@0 | 2062 | } |
michael@0 | 2063 | } |
michael@0 | 2064 | ucol_closeElements(colEl); |
michael@0 | 2065 | ucol_close(tempColl); |
michael@0 | 2066 | |
michael@0 | 2067 | return context.noOfClosures; |
michael@0 | 2068 | } |
michael@0 | 2069 | |
michael@0 | 2070 | #endif /* #if !UCONFIG_NO_COLLATION */ |