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