intl/icu/source/i18n/ucol_elm.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

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 */

mercurial