/work/workdir/UnpackedTarball/fontconfig/src/fccharset.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * fontconfig/src/fccharset.c |
3 | | * |
4 | | * Copyright © 2001 Keith Packard |
5 | | * |
6 | | * Permission to use, copy, modify, distribute, and sell this software and its |
7 | | * documentation for any purpose is hereby granted without fee, provided that |
8 | | * the above copyright notice appear in all copies and that both that |
9 | | * copyright notice and this permission notice appear in supporting |
10 | | * documentation, and that the name of the author(s) not be used in |
11 | | * advertising or publicity pertaining to distribution of the software without |
12 | | * specific, written prior permission. The authors make no |
13 | | * representations about the suitability of this software for any purpose. It |
14 | | * is provided "as is" without express or implied warranty. |
15 | | * |
16 | | * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
17 | | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
18 | | * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
19 | | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
20 | | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
21 | | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
22 | | * PERFORMANCE OF THIS SOFTWARE. |
23 | | */ |
24 | | |
25 | | #include "fcint.h" |
26 | | |
27 | | #include <stdlib.h> |
28 | | |
29 | | /* #define CHECK */ |
30 | | |
31 | | FcCharSet * |
32 | | FcCharSetCreate (void) |
33 | 26 | { |
34 | 26 | FcCharSet *fcs; |
35 | | |
36 | 26 | fcs = (FcCharSet *)malloc (sizeof (FcCharSet)); |
37 | 26 | if (!fcs) |
38 | 0 | return 0; |
39 | 26 | FcRefInit (&fcs->ref, 1); |
40 | 26 | fcs->num = 0; |
41 | 26 | fcs->leaves_offset = 0; |
42 | 26 | fcs->numbers_offset = 0; |
43 | 26 | return fcs; |
44 | 26 | } |
45 | | |
46 | | FcCharSet * |
47 | | FcCharSetPromote (FcValuePromotionBuffer *vbuf) |
48 | 0 | { |
49 | 0 | FcCharSet *fcs = (FcCharSet *)vbuf; |
50 | |
|
51 | 0 | FC_ASSERT_STATIC (sizeof (FcCharSet) <= sizeof (FcValuePromotionBuffer)); |
52 | |
|
53 | 0 | FcRefSetConst (&fcs->ref); |
54 | 0 | fcs->num = 0; |
55 | 0 | fcs->leaves_offset = 0; |
56 | 0 | fcs->numbers_offset = 0; |
57 | |
|
58 | 0 | return fcs; |
59 | 0 | } |
60 | | |
61 | | FcCharSet * |
62 | | FcCharSetNew (void) |
63 | 0 | { |
64 | 0 | return FcCharSetCreate(); |
65 | 0 | } |
66 | | |
67 | | void |
68 | | FcCharSetDestroy (FcCharSet *fcs) |
69 | 4.17k | { |
70 | 4.17k | int i; |
71 | | |
72 | 4.17k | if (fcs) { |
73 | 4.16k | if (FcRefIsConst (&fcs->ref)) { |
74 | 4.12k | FcCacheObjectDereference (fcs); |
75 | 4.12k | return; |
76 | 4.12k | } |
77 | 39 | if (FcRefDec (&fcs->ref) != 1) |
78 | 26 | return; |
79 | 288 | for (i = 0; i < fcs->num; i++) |
80 | 275 | free (FcCharSetLeaf (fcs, i)); |
81 | 13 | if (fcs->num) { |
82 | 13 | free (FcCharSetLeaves (fcs)); |
83 | 13 | free (FcCharSetNumbers (fcs)); |
84 | 13 | } |
85 | 13 | free (fcs); |
86 | 13 | } |
87 | 4.17k | } |
88 | | |
89 | | /* |
90 | | * Search for the leaf containing with the specified num. |
91 | | * Return its index if it exists, otherwise return negative of |
92 | | * the (position + 1) where it should be inserted |
93 | | */ |
94 | | |
95 | | static int |
96 | | FcCharSetFindLeafForward (const FcCharSet *fcs, int start, FcChar16 num) |
97 | 40.0k | { |
98 | 40.0k | FcChar16 *numbers = FcCharSetNumbers (fcs); |
99 | 40.0k | FcChar16 page; |
100 | 40.0k | int low = start; |
101 | 40.0k | int high = fcs->num - 1; |
102 | | |
103 | 40.0k | if (!numbers) |
104 | 0 | return -1; |
105 | 125k | while (low <= high) { |
106 | 121k | int mid = (low + high) >> 1; |
107 | 121k | page = numbers[mid]; |
108 | 121k | if (page == num) |
109 | 36.6k | return mid; |
110 | 85.2k | if (page < num) |
111 | 64.5k | low = mid + 1; |
112 | 20.7k | else |
113 | 20.7k | high = mid - 1; |
114 | 85.2k | } |
115 | 3.38k | if (high < 0 || (high < fcs->num && numbers[high] < num)) |
116 | 3.38k | high++; |
117 | 3.38k | return -(high + 1); |
118 | 40.0k | } |
119 | | |
120 | | /* |
121 | | * Locate the leaf containing the specified char, return |
122 | | * its index if it exists, otherwise return negative of |
123 | | * the (position + 1) where it should be inserted |
124 | | */ |
125 | | |
126 | | static int |
127 | | FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4) |
128 | 40.0k | { |
129 | 40.0k | return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8); |
130 | 40.0k | } |
131 | | |
132 | | static FcCharLeaf * |
133 | | FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4) |
134 | 0 | { |
135 | 0 | int pos = FcCharSetFindLeafPos (fcs, ucs4); |
136 | 0 | if (pos >= 0) |
137 | 0 | return FcCharSetLeaf (fcs, pos); |
138 | 0 | return 0; |
139 | 0 | } |
140 | | |
141 | 550 | #define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x) - 1))) |
142 | | |
143 | | static FcBool |
144 | | FcCharSetPutLeaf (FcCharSet *fcs, |
145 | | FcChar32 ucs4, |
146 | | FcCharLeaf *leaf, |
147 | | int pos) |
148 | 550 | { |
149 | 550 | intptr_t *leaves = FcCharSetLeaves (fcs); |
150 | 550 | FcChar16 *numbers = FcCharSetNumbers (fcs); |
151 | | |
152 | 550 | ucs4 >>= 8; |
153 | 550 | if (ucs4 >= 0x10000) |
154 | 0 | return FcFalse; |
155 | | |
156 | 550 | if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num)) { |
157 | 156 | if (!fcs->num) { |
158 | 26 | unsigned int alloced = 8; |
159 | 26 | leaves = malloc (alloced * sizeof (*leaves)); |
160 | 26 | numbers = malloc (alloced * sizeof (*numbers)); |
161 | 26 | if (!leaves || !numbers) { |
162 | 0 | if (leaves) |
163 | 0 | free (leaves); |
164 | 0 | if (numbers) |
165 | 0 | free (numbers); |
166 | 0 | return FcFalse; |
167 | 0 | } |
168 | 130 | } else { |
169 | 130 | int i; |
170 | 130 | unsigned int alloced = fcs->num; |
171 | 130 | intptr_t *new_leaves; |
172 | | |
173 | 130 | alloced *= 2; |
174 | 130 | numbers = realloc (numbers, alloced * sizeof (*numbers)); |
175 | 130 | if (!numbers) |
176 | 0 | return FcFalse; |
177 | 130 | new_leaves = realloc (leaves, alloced * sizeof (*leaves)); |
178 | 130 | if (!new_leaves) { |
179 | | /* |
180 | | * Revert the reallocation of numbers. We update numbers_offset |
181 | | * first in case realloc() fails. |
182 | | */ |
183 | 0 | fcs->numbers_offset = FcPtrToOffset (fcs, numbers); |
184 | 0 | numbers = realloc (numbers, (alloced / 2) * sizeof (*numbers)); |
185 | | /* unlikely to fail though */ |
186 | 0 | if (!numbers) |
187 | 0 | return FcFalse; |
188 | 0 | fcs->numbers_offset = FcPtrToOffset (fcs, numbers); |
189 | 0 | return FcFalse; |
190 | 0 | } |
191 | 936 | for (i = 0; i < fcs->num; i++) { |
192 | | // Reconstruct FcCharLeaf* from offset, similar to how FcCharSetLeaf() macro operates |
193 | 806 | FcCharLeaf *leaf = FcOffsetToPtr (leaves, new_leaves[i], FcCharLeaf); |
194 | 806 | new_leaves[i] = FcPtrToOffset (new_leaves, leaf); |
195 | 806 | } |
196 | 130 | leaves = new_leaves; |
197 | 130 | } |
198 | | |
199 | 156 | fcs->leaves_offset = FcPtrToOffset (fcs, leaves); |
200 | 156 | fcs->numbers_offset = FcPtrToOffset (fcs, numbers); |
201 | 156 | } |
202 | | |
203 | 550 | memmove (leaves + pos + 1, leaves + pos, |
204 | 550 | (fcs->num - pos) * sizeof (*leaves)); |
205 | 550 | memmove (numbers + pos + 1, numbers + pos, |
206 | 550 | (fcs->num - pos) * sizeof (*numbers)); |
207 | 550 | numbers[pos] = (FcChar16)ucs4; |
208 | 550 | leaves[pos] = FcPtrToOffset (leaves, leaf); |
209 | 550 | fcs->num++; |
210 | 550 | return FcTrue; |
211 | 550 | } |
212 | | |
213 | | /* |
214 | | * Locate the leaf containing the specified char, creating it |
215 | | * if desired |
216 | | */ |
217 | | |
218 | | FcCharLeaf * |
219 | | FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4) |
220 | 28.8k | { |
221 | 28.8k | int pos; |
222 | 28.8k | FcCharLeaf *leaf; |
223 | | |
224 | 28.8k | pos = FcCharSetFindLeafPos (fcs, ucs4); |
225 | 28.8k | if (pos >= 0) |
226 | 28.6k | return FcCharSetLeaf (fcs, pos); |
227 | | |
228 | 275 | leaf = calloc (1, sizeof (FcCharLeaf)); |
229 | 275 | if (!leaf) |
230 | 0 | return 0; |
231 | | |
232 | 275 | pos = -pos - 1; |
233 | 275 | if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos)) { |
234 | 0 | free (leaf); |
235 | 0 | return 0; |
236 | 0 | } |
237 | 275 | return leaf; |
238 | 275 | } |
239 | | |
240 | | static FcBool |
241 | | FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf) |
242 | 275 | { |
243 | 275 | int pos; |
244 | | |
245 | 275 | pos = FcCharSetFindLeafPos (fcs, ucs4); |
246 | 275 | if (pos >= 0) { |
247 | 0 | free (FcCharSetLeaf (fcs, pos)); |
248 | 0 | FcCharSetLeaves (fcs)[pos] = FcPtrToOffset (FcCharSetLeaves (fcs), |
249 | 0 | leaf); |
250 | 0 | return FcTrue; |
251 | 0 | } |
252 | 275 | pos = -pos - 1; |
253 | 275 | return FcCharSetPutLeaf (fcs, ucs4, leaf, pos); |
254 | 275 | } |
255 | | |
256 | | FcBool |
257 | | FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4) |
258 | 28.8k | { |
259 | 28.8k | FcCharLeaf *leaf; |
260 | 28.8k | FcChar32 *b; |
261 | | |
262 | 28.8k | if (fcs == NULL || FcRefIsConst (&fcs->ref)) |
263 | 0 | return FcFalse; |
264 | 28.8k | leaf = FcCharSetFindLeafCreate (fcs, ucs4); |
265 | 28.8k | if (!leaf) |
266 | 0 | return FcFalse; |
267 | 28.8k | b = &leaf->map[(ucs4 & 0xff) >> 5]; |
268 | 28.8k | *b |= (1U << (ucs4 & 0x1f)); |
269 | 28.8k | return FcTrue; |
270 | 28.8k | } |
271 | | |
272 | | FcBool |
273 | | FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4) |
274 | 0 | { |
275 | 0 | FcCharLeaf *leaf; |
276 | 0 | FcChar32 *b; |
277 | |
|
278 | 0 | if (fcs == NULL || FcRefIsConst (&fcs->ref)) |
279 | 0 | return FcFalse; |
280 | 0 | leaf = FcCharSetFindLeaf (fcs, ucs4); |
281 | 0 | if (!leaf) |
282 | 0 | return FcTrue; |
283 | 0 | b = &leaf->map[(ucs4 & 0xff) >> 5]; |
284 | 0 | *b &= ~(1U << (ucs4 & 0x1f)); |
285 | | /* We don't bother removing the leaf if it's empty */ |
286 | 0 | return FcTrue; |
287 | 0 | } |
288 | | |
289 | | /* |
290 | | * An iterator for the leaves of a charset |
291 | | */ |
292 | | |
293 | | typedef struct _fcCharSetIter { |
294 | | FcCharLeaf *leaf; |
295 | | FcChar32 ucs4; |
296 | | int pos; |
297 | | } FcCharSetIter; |
298 | | |
299 | | /* |
300 | | * Set iter->leaf to the leaf containing iter->ucs4 or higher |
301 | | */ |
302 | | |
303 | | static void |
304 | | FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter) |
305 | 10.8k | { |
306 | 10.8k | int pos = FcCharSetFindLeafPos (fcs, iter->ucs4); |
307 | | |
308 | 10.8k | if (pos < 0) { |
309 | 2.83k | pos = -pos - 1; |
310 | 2.83k | if (pos == fcs->num) { |
311 | 83 | iter->ucs4 = ~0; |
312 | 83 | iter->leaf = 0; |
313 | 83 | return; |
314 | 83 | } |
315 | 2.75k | iter->ucs4 = (FcChar32)FcCharSetNumbers (fcs)[pos] << 8; |
316 | 2.75k | } |
317 | 10.8k | iter->leaf = FcCharSetLeaf (fcs, pos); |
318 | 10.8k | iter->pos = pos; |
319 | 10.8k | } |
320 | | |
321 | | static void |
322 | | FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter) |
323 | 21.8k | { |
324 | 21.8k | int pos = iter->pos + 1; |
325 | 21.8k | if (pos >= fcs->num) { |
326 | 3.66k | iter->ucs4 = ~0; |
327 | 3.66k | iter->leaf = 0; |
328 | 18.1k | } else { |
329 | 18.1k | iter->ucs4 = (FcChar32)FcCharSetNumbers (fcs)[pos] << 8; |
330 | 18.1k | iter->leaf = FcCharSetLeaf (fcs, pos); |
331 | 18.1k | iter->pos = pos; |
332 | 18.1k | } |
333 | 21.8k | } |
334 | | |
335 | | static void |
336 | | FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter) |
337 | 7.31k | { |
338 | 7.31k | iter->ucs4 = 0; |
339 | 7.31k | iter->pos = 0; |
340 | 7.31k | FcCharSetIterSet (fcs, iter); |
341 | 7.31k | } |
342 | | |
343 | | FcCharSet * |
344 | | FcCharSetCopy (FcCharSet *src) |
345 | 4.18k | { |
346 | 4.18k | if (src) { |
347 | 4.18k | if (!FcRefIsConst (&src->ref)) |
348 | 26 | FcRefInc (&src->ref); |
349 | 4.15k | else |
350 | 4.15k | FcCacheObjectReference (src); |
351 | 4.18k | } |
352 | 4.18k | return src; |
353 | 4.18k | } |
354 | | |
355 | | FcBool |
356 | | FcCharSetEqual (const FcCharSet *a, const FcCharSet *b) |
357 | 0 | { |
358 | 0 | FcCharSetIter ai, bi; |
359 | 0 | int i; |
360 | |
|
361 | 0 | if (a == b) |
362 | 0 | return FcTrue; |
363 | 0 | if (!a || !b) |
364 | 0 | return FcFalse; |
365 | 0 | for (FcCharSetIterStart (a, &ai), FcCharSetIterStart (b, &bi); |
366 | 0 | ai.leaf && bi.leaf; |
367 | 0 | FcCharSetIterNext (a, &ai), FcCharSetIterNext (b, &bi)) { |
368 | 0 | if (ai.ucs4 != bi.ucs4) |
369 | 0 | return FcFalse; |
370 | 0 | for (i = 0; i < 256 / 32; i++) |
371 | 0 | if (ai.leaf->map[i] != bi.leaf->map[i]) |
372 | 0 | return FcFalse; |
373 | 0 | } |
374 | 0 | return ai.leaf == bi.leaf; |
375 | 0 | } |
376 | | |
377 | | static FcBool |
378 | | FcCharSetAddLeaf (FcCharSet *fcs, |
379 | | FcChar32 ucs4, |
380 | | FcCharLeaf *leaf) |
381 | 0 | { |
382 | 0 | FcCharLeaf *newp = FcCharSetFindLeafCreate (fcs, ucs4); |
383 | 0 | if (!newp) |
384 | 0 | return FcFalse; |
385 | 0 | *newp = *leaf; |
386 | 0 | return FcTrue; |
387 | 0 | } |
388 | | |
389 | | static FcCharSet * |
390 | | FcCharSetOperate (const FcCharSet *a, |
391 | | const FcCharSet *b, |
392 | | FcBool (*overlap) (FcCharLeaf *result, |
393 | | const FcCharLeaf *al, |
394 | | const FcCharLeaf *bl), |
395 | | FcBool aonly, |
396 | | FcBool bonly) |
397 | 0 | { |
398 | 0 | FcCharSet *fcs; |
399 | 0 | FcCharSetIter ai, bi; |
400 | |
|
401 | 0 | if (!a || !b) |
402 | 0 | goto bail0; |
403 | 0 | fcs = FcCharSetCreate(); |
404 | 0 | if (!fcs) |
405 | 0 | goto bail0; |
406 | 0 | FcCharSetIterStart (a, &ai); |
407 | 0 | FcCharSetIterStart (b, &bi); |
408 | 0 | while ((ai.leaf || (bonly && bi.leaf)) && (bi.leaf || (aonly && ai.leaf))) { |
409 | 0 | if (ai.ucs4 < bi.ucs4) { |
410 | 0 | if (aonly) { |
411 | 0 | if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf)) |
412 | 0 | goto bail1; |
413 | 0 | FcCharSetIterNext (a, &ai); |
414 | 0 | } else { |
415 | 0 | ai.ucs4 = bi.ucs4; |
416 | 0 | FcCharSetIterSet (a, &ai); |
417 | 0 | } |
418 | 0 | } else if (bi.ucs4 < ai.ucs4) { |
419 | 0 | if (bonly) { |
420 | 0 | if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf)) |
421 | 0 | goto bail1; |
422 | 0 | FcCharSetIterNext (b, &bi); |
423 | 0 | } else { |
424 | 0 | bi.ucs4 = ai.ucs4; |
425 | 0 | FcCharSetIterSet (b, &bi); |
426 | 0 | } |
427 | 0 | } else { |
428 | 0 | FcCharLeaf leaf; |
429 | |
|
430 | 0 | if ((*overlap) (&leaf, ai.leaf, bi.leaf)) { |
431 | 0 | if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf)) |
432 | 0 | goto bail1; |
433 | 0 | } |
434 | 0 | FcCharSetIterNext (a, &ai); |
435 | 0 | FcCharSetIterNext (b, &bi); |
436 | 0 | } |
437 | 0 | } |
438 | 0 | return fcs; |
439 | 0 | bail1: |
440 | 0 | FcCharSetDestroy (fcs); |
441 | 0 | bail0: |
442 | 0 | return 0; |
443 | 0 | } |
444 | | |
445 | | static FcBool |
446 | | FcCharSetIntersectLeaf (FcCharLeaf *result, |
447 | | const FcCharLeaf *al, |
448 | | const FcCharLeaf *bl) |
449 | 0 | { |
450 | 0 | int i; |
451 | 0 | FcBool nonempty = FcFalse; |
452 | |
|
453 | 0 | for (i = 0; i < 256 / 32; i++) |
454 | 0 | if ((result->map[i] = al->map[i] & bl->map[i])) |
455 | 0 | nonempty = FcTrue; |
456 | 0 | return nonempty; |
457 | 0 | } |
458 | | |
459 | | FcCharSet * |
460 | | FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b) |
461 | 0 | { |
462 | 0 | return FcCharSetOperate (a, b, FcCharSetIntersectLeaf, FcFalse, FcFalse); |
463 | 0 | } |
464 | | |
465 | | static FcBool |
466 | | FcCharSetUnionLeaf (FcCharLeaf *result, |
467 | | const FcCharLeaf *al, |
468 | | const FcCharLeaf *bl) |
469 | 0 | { |
470 | 0 | int i; |
471 | |
|
472 | 0 | for (i = 0; i < 256 / 32; i++) |
473 | 0 | result->map[i] = al->map[i] | bl->map[i]; |
474 | 0 | return FcTrue; |
475 | 0 | } |
476 | | |
477 | | FcCharSet * |
478 | | FcCharSetUnion (const FcCharSet *a, const FcCharSet *b) |
479 | 0 | { |
480 | 0 | return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue); |
481 | 0 | } |
482 | | |
483 | | FcBool |
484 | | FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed) |
485 | 0 | { |
486 | 0 | int ai = 0, bi = 0; |
487 | 0 | FcChar16 an, bn; |
488 | |
|
489 | 0 | if (!a || !b) |
490 | 0 | return FcFalse; |
491 | | |
492 | 0 | if (FcRefIsConst (&a->ref)) { |
493 | 0 | if (changed) |
494 | 0 | *changed = FcFalse; |
495 | 0 | return FcFalse; |
496 | 0 | } |
497 | | |
498 | 0 | if (changed) { |
499 | 0 | *changed = !FcCharSetIsSubset (b, a); |
500 | 0 | if (!*changed) |
501 | 0 | return FcTrue; |
502 | 0 | } |
503 | | |
504 | 0 | while (bi < b->num) { |
505 | 0 | an = ai < a->num ? FcCharSetNumbers (a)[ai] : ~0; |
506 | 0 | bn = FcCharSetNumbers (b)[bi]; |
507 | |
|
508 | 0 | if (an < bn) { |
509 | 0 | ai = FcCharSetFindLeafForward (a, ai + 1, bn); |
510 | 0 | if (ai < 0) |
511 | 0 | ai = -ai - 1; |
512 | 0 | } else { |
513 | 0 | FcCharLeaf *bl = FcCharSetLeaf (b, bi); |
514 | 0 | if (bn < an) { |
515 | 0 | if (!FcCharSetAddLeaf (a, bn << 8, bl)) |
516 | 0 | return FcFalse; |
517 | 0 | } else { |
518 | 0 | FcCharLeaf *al = FcCharSetLeaf (a, ai); |
519 | 0 | FcCharSetUnionLeaf (al, al, bl); |
520 | 0 | } |
521 | | |
522 | 0 | ai++; |
523 | 0 | bi++; |
524 | 0 | } |
525 | 0 | } |
526 | | |
527 | 0 | return FcTrue; |
528 | 0 | } |
529 | | |
530 | | static FcBool |
531 | | FcCharSetSubtractLeaf (FcCharLeaf *result, |
532 | | const FcCharLeaf *al, |
533 | | const FcCharLeaf *bl) |
534 | 0 | { |
535 | 0 | int i; |
536 | 0 | FcBool nonempty = FcFalse; |
537 | |
|
538 | 0 | for (i = 0; i < 256 / 32; i++) |
539 | 0 | if ((result->map[i] = al->map[i] & ~bl->map[i])) |
540 | 0 | nonempty = FcTrue; |
541 | 0 | return nonempty; |
542 | 0 | } |
543 | | |
544 | | FcCharSet * |
545 | | FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b) |
546 | 0 | { |
547 | 0 | return FcCharSetOperate (a, b, FcCharSetSubtractLeaf, FcTrue, FcFalse); |
548 | 0 | } |
549 | | |
550 | | FcBool |
551 | | FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4) |
552 | 0 | { |
553 | 0 | FcCharLeaf *leaf; |
554 | |
|
555 | 0 | if (!fcs) |
556 | 0 | return FcFalse; |
557 | 0 | leaf = FcCharSetFindLeaf (fcs, ucs4); |
558 | 0 | if (!leaf) |
559 | 0 | return FcFalse; |
560 | 0 | return (leaf->map[(ucs4 & 0xff) >> 5] & (1U << (ucs4 & 0x1f))) != 0; |
561 | 0 | } |
562 | | |
563 | | static FcChar32 |
564 | | FcCharSetPopCount (FcChar32 c1) |
565 | 174k | { |
566 | 174k | #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) |
567 | 174k | return __builtin_popcount (c1); |
568 | | #else |
569 | | /* hackmem 169 */ |
570 | | FcChar32 c2 = (c1 >> 1) & 033333333333; |
571 | | c2 = c1 - c2 - ((c2 >> 1) & 033333333333); |
572 | | return (((c2 + (c2 >> 3)) & 030707070707) % 077); |
573 | | #endif |
574 | 174k | } |
575 | | |
576 | | FcChar32 |
577 | | FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b) |
578 | 0 | { |
579 | 0 | FcCharSetIter ai, bi; |
580 | 0 | FcChar32 count = 0; |
581 | |
|
582 | 0 | if (a && b) { |
583 | 0 | FcCharSetIterStart (a, &ai); |
584 | 0 | FcCharSetIterStart (b, &bi); |
585 | 0 | while (ai.leaf && bi.leaf) { |
586 | 0 | if (ai.ucs4 == bi.ucs4) { |
587 | 0 | FcChar32 *am = ai.leaf->map; |
588 | 0 | FcChar32 *bm = bi.leaf->map; |
589 | 0 | int i = 256 / 32; |
590 | 0 | while (i--) |
591 | 0 | count += FcCharSetPopCount (*am++ & *bm++); |
592 | 0 | FcCharSetIterNext (a, &ai); |
593 | 0 | } else if (ai.ucs4 < bi.ucs4) { |
594 | 0 | ai.ucs4 = bi.ucs4; |
595 | 0 | FcCharSetIterSet (a, &ai); |
596 | 0 | } |
597 | 0 | if (bi.ucs4 < ai.ucs4) { |
598 | 0 | bi.ucs4 = ai.ucs4; |
599 | 0 | FcCharSetIterSet (b, &bi); |
600 | 0 | } |
601 | 0 | } |
602 | 0 | } |
603 | 0 | return count; |
604 | 0 | } |
605 | | |
606 | | FcChar32 |
607 | | FcCharSetCount (const FcCharSet *a) |
608 | 13 | { |
609 | 13 | FcCharSetIter ai; |
610 | 13 | FcChar32 count = 0; |
611 | | |
612 | 13 | if (a) { |
613 | 288 | for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai)) { |
614 | 275 | int i = 256 / 32; |
615 | 275 | FcChar32 *am = ai.leaf->map; |
616 | | |
617 | 2.47k | while (i--) |
618 | 2.20k | count += FcCharSetPopCount (*am++); |
619 | 275 | } |
620 | 13 | } |
621 | 13 | return count; |
622 | 13 | } |
623 | | |
624 | | FcChar32 |
625 | | FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b) |
626 | 3.65k | { |
627 | 3.65k | FcCharSetIter ai, bi; |
628 | 3.65k | FcChar32 count = 0; |
629 | | |
630 | 3.65k | if (a && b) { |
631 | 3.65k | FcCharSetIterStart (a, &ai); |
632 | 3.65k | FcCharSetIterStart (b, &bi); |
633 | 28.7k | while (ai.leaf) { |
634 | 25.1k | if (ai.ucs4 <= bi.ucs4) { |
635 | 21.5k | FcChar32 *am = ai.leaf->map; |
636 | 21.5k | int i = 256 / 32; |
637 | 21.5k | if (ai.ucs4 == bi.ucs4) { |
638 | 4.39k | FcChar32 *bm = bi.leaf->map; |
639 | 39.5k | while (i--) |
640 | 35.1k | count += FcCharSetPopCount (*am++ & ~*bm++); |
641 | 17.1k | } else { |
642 | 154k | while (i--) |
643 | 137k | count += FcCharSetPopCount (*am++); |
644 | 17.1k | } |
645 | 21.5k | FcCharSetIterNext (a, &ai); |
646 | 21.5k | } else if (bi.leaf) { |
647 | 3.57k | bi.ucs4 = ai.ucs4; |
648 | 3.57k | FcCharSetIterSet (b, &bi); |
649 | 3.57k | } |
650 | 25.1k | } |
651 | 3.65k | } |
652 | 3.65k | return count; |
653 | 3.65k | } |
654 | | |
655 | | /* |
656 | | * return FcTrue iff a is a subset of b |
657 | | */ |
658 | | FcBool |
659 | | FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b) |
660 | 0 | { |
661 | 0 | int ai, bi; |
662 | 0 | FcChar16 an, bn; |
663 | |
|
664 | 0 | if (a == b) |
665 | 0 | return FcTrue; |
666 | 0 | if (!a || !b) |
667 | 0 | return FcFalse; |
668 | 0 | bi = 0; |
669 | 0 | ai = 0; |
670 | 0 | while (ai < a->num && bi < b->num) { |
671 | 0 | an = FcCharSetNumbers (a)[ai]; |
672 | 0 | bn = FcCharSetNumbers (b)[bi]; |
673 | | /* |
674 | | * Check matching pages |
675 | | */ |
676 | 0 | if (an == bn) { |
677 | 0 | FcChar32 *am = FcCharSetLeaf (a, ai)->map; |
678 | 0 | FcChar32 *bm = FcCharSetLeaf (b, bi)->map; |
679 | |
|
680 | 0 | if (am != bm) { |
681 | 0 | int i = 256 / 32; |
682 | | /* |
683 | | * Does am have any bits not in bm? |
684 | | */ |
685 | 0 | while (i--) |
686 | 0 | if (*am++ & ~*bm++) |
687 | 0 | return FcFalse; |
688 | 0 | } |
689 | 0 | ai++; |
690 | 0 | bi++; |
691 | 0 | } |
692 | | /* |
693 | | * Does a have any pages not in b? |
694 | | */ |
695 | 0 | else if (an < bn) |
696 | 0 | return FcFalse; |
697 | 0 | else { |
698 | 0 | bi = FcCharSetFindLeafForward (b, bi + 1, an); |
699 | 0 | if (bi < 0) |
700 | 0 | bi = -bi - 1; |
701 | 0 | } |
702 | 0 | } |
703 | | /* |
704 | | * did we look at every page? |
705 | | */ |
706 | 0 | return ai >= a->num; |
707 | 0 | } |
708 | | |
709 | | /* |
710 | | * These two functions efficiently walk the entire charmap for |
711 | | * other software (like pango) that want their own copy |
712 | | */ |
713 | | |
714 | | FcChar32 |
715 | | FcCharSetNextPage (const FcCharSet *a, |
716 | | FcChar32 map[FC_CHARSET_MAP_SIZE], |
717 | | FcChar32 *next) |
718 | 0 | { |
719 | 0 | FcCharSetIter ai; |
720 | 0 | FcChar32 page; |
721 | |
|
722 | 0 | if (!a) |
723 | 0 | return FC_CHARSET_DONE; |
724 | 0 | ai.ucs4 = *next; |
725 | 0 | FcCharSetIterSet (a, &ai); |
726 | 0 | if (!ai.leaf) |
727 | 0 | return FC_CHARSET_DONE; |
728 | | |
729 | | /* |
730 | | * Save current information |
731 | | */ |
732 | 0 | page = ai.ucs4; |
733 | 0 | memcpy (map, ai.leaf->map, sizeof (ai.leaf->map)); |
734 | | /* |
735 | | * Step to next page |
736 | | */ |
737 | 0 | FcCharSetIterNext (a, &ai); |
738 | 0 | *next = ai.ucs4; |
739 | |
|
740 | 0 | return page; |
741 | 0 | } |
742 | | |
743 | | FcChar32 |
744 | | FcCharSetFirstPage (const FcCharSet *a, |
745 | | FcChar32 map[FC_CHARSET_MAP_SIZE], |
746 | | FcChar32 *next) |
747 | 0 | { |
748 | 0 | *next = 0; |
749 | 0 | return FcCharSetNextPage (a, map, next); |
750 | 0 | } |
751 | | |
752 | | /* |
753 | | * old coverage API, rather hard to use correctly |
754 | | */ |
755 | | |
756 | | FcChar32 |
757 | | FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result) |
758 | 0 | { |
759 | 0 | FcCharSetIter ai; |
760 | |
|
761 | 0 | ai.ucs4 = page; |
762 | 0 | FcCharSetIterSet (a, &ai); |
763 | 0 | if (!ai.leaf) { |
764 | 0 | memset (result, '\0', 256 / 8); |
765 | 0 | page = 0; |
766 | 0 | } else { |
767 | 0 | memcpy (result, ai.leaf->map, sizeof (ai.leaf->map)); |
768 | 0 | FcCharSetIterNext (a, &ai); |
769 | 0 | page = ai.ucs4; |
770 | 0 | } |
771 | 0 | return page; |
772 | 0 | } |
773 | | |
774 | | static FcBool |
775 | | FcNameParseRange (FcChar8 **string, FcChar32 *pfirst, FcChar32 *plast) |
776 | 0 | { |
777 | 0 | char *s = (char *)*string; |
778 | 0 | char *t; |
779 | 0 | long first, last; |
780 | |
|
781 | 0 | while (isspace ((unsigned char)*s)) |
782 | 0 | s++; |
783 | 0 | t = s; |
784 | 0 | errno = 0; |
785 | 0 | first = last = strtol (s, &s, 16); |
786 | 0 | if (errno) |
787 | 0 | return FcFalse; |
788 | 0 | while (isspace ((unsigned char)*s)) |
789 | 0 | s++; |
790 | 0 | if (*s == '-') { |
791 | 0 | s++; |
792 | 0 | errno = 0; |
793 | 0 | last = strtol (s, &s, 16); |
794 | 0 | if (errno) |
795 | 0 | return FcFalse; |
796 | 0 | } |
797 | | |
798 | 0 | if (s == t || first < 0 || last < 0 || last < first || last > 0x10ffff) |
799 | 0 | return FcFalse; |
800 | | |
801 | 0 | *string = (FcChar8 *)s; |
802 | 0 | *pfirst = first; |
803 | 0 | *plast = last; |
804 | 0 | return FcTrue; |
805 | 0 | } |
806 | | |
807 | | FcCharSet * |
808 | | FcNameParseCharSet (FcChar8 *string) |
809 | 0 | { |
810 | 0 | FcCharSet *c; |
811 | 0 | FcChar32 first, last; |
812 | |
|
813 | 0 | c = FcCharSetCreate(); |
814 | 0 | if (!c) |
815 | 0 | goto bail0; |
816 | 0 | while (*string) { |
817 | 0 | FcChar32 u; |
818 | |
|
819 | 0 | if (!FcNameParseRange (&string, &first, &last)) |
820 | 0 | goto bail1; |
821 | | |
822 | 0 | for (u = first; u < last + 1; u++) |
823 | 0 | FcCharSetAddChar (c, u); |
824 | 0 | } |
825 | 0 | return c; |
826 | 0 | bail1: |
827 | 0 | FcCharSetDestroy (c); |
828 | 0 | bail0: |
829 | 0 | return NULL; |
830 | 0 | } |
831 | | |
832 | | static void |
833 | | FcNameUnparseUnicode (FcStrBuf *buf, FcChar32 u) |
834 | 0 | { |
835 | 0 | FcChar8 buf_static[64]; |
836 | 0 | snprintf ((char *)buf_static, sizeof (buf_static), "%x", u); |
837 | 0 | FcStrBufString (buf, buf_static); |
838 | 0 | } |
839 | | |
840 | | FcBool |
841 | | FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c) |
842 | 0 | { |
843 | 0 | FcCharSetIter ci; |
844 | 0 | FcChar32 first, last; |
845 | 0 | int i; |
846 | | #ifdef CHECK |
847 | | int len = buf->len; |
848 | | #endif |
849 | |
|
850 | 0 | first = last = 0x7FFFFFFF; |
851 | |
|
852 | 0 | for (FcCharSetIterStart (c, &ci); |
853 | 0 | ci.leaf; |
854 | 0 | FcCharSetIterNext (c, &ci)) { |
855 | 0 | for (i = 0; i < 256 / 32; i++) { |
856 | 0 | FcChar32 bits = ci.leaf->map[i]; |
857 | 0 | FcChar32 u = ci.ucs4 + i * 32; |
858 | |
|
859 | 0 | while (bits) { |
860 | 0 | if (bits & 1) { |
861 | 0 | if (u != last + 1) { |
862 | 0 | if (last != first) { |
863 | 0 | FcStrBufChar (buf, '-'); |
864 | 0 | FcNameUnparseUnicode (buf, last); |
865 | 0 | } |
866 | 0 | if (last != 0x7FFFFFFF) |
867 | 0 | FcStrBufChar (buf, ' '); |
868 | | /* Start new range. */ |
869 | 0 | first = u; |
870 | 0 | FcNameUnparseUnicode (buf, u); |
871 | 0 | } |
872 | 0 | last = u; |
873 | 0 | } |
874 | 0 | bits >>= 1; |
875 | 0 | u++; |
876 | 0 | } |
877 | 0 | } |
878 | 0 | } |
879 | 0 | if (last != first) { |
880 | 0 | FcStrBufChar (buf, '-'); |
881 | 0 | FcNameUnparseUnicode (buf, last); |
882 | 0 | } |
883 | | #ifdef CHECK |
884 | | { |
885 | | FcCharSet *check; |
886 | | FcChar32 missing; |
887 | | FcCharSetIter ci, checki; |
888 | | |
889 | | /* null terminate for parser */ |
890 | | FcStrBufChar (buf, '\0'); |
891 | | /* step back over null for life after test */ |
892 | | buf->len--; |
893 | | check = FcNameParseCharSet (buf->buf + len); |
894 | | FcCharSetIterStart (c, &ci); |
895 | | FcCharSetIterStart (check, &checki); |
896 | | while (ci.leaf || checki.leaf) { |
897 | | if (ci.ucs4 < checki.ucs4) { |
898 | | printf ("Missing leaf node at 0x%x\n", ci.ucs4); |
899 | | FcCharSetIterNext (c, &ci); |
900 | | } else if (checki.ucs4 < ci.ucs4) { |
901 | | printf ("Extra leaf node at 0x%x\n", checki.ucs4); |
902 | | FcCharSetIterNext (check, &checki); |
903 | | } else { |
904 | | int i = 256 / 32; |
905 | | FcChar32 *cm = ci.leaf->map; |
906 | | FcChar32 *checkm = checki.leaf->map; |
907 | | |
908 | | for (i = 0; i < 256; i += 32) { |
909 | | if (*cm != *checkm) |
910 | | printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n", |
911 | | ci.ucs4 + i, *cm, *checkm); |
912 | | cm++; |
913 | | checkm++; |
914 | | } |
915 | | FcCharSetIterNext (c, &ci); |
916 | | FcCharSetIterNext (check, &checki); |
917 | | } |
918 | | } |
919 | | if ((missing = FcCharSetSubtractCount (c, check))) |
920 | | printf ("%d missing in reparsed result\n", missing); |
921 | | if ((missing = FcCharSetSubtractCount (check, c))) |
922 | | printf ("%d extra in reparsed result\n", missing); |
923 | | FcCharSetDestroy (check); |
924 | | } |
925 | | #endif |
926 | |
|
927 | 0 | return FcTrue; |
928 | 0 | } |
929 | | |
930 | | typedef struct _FcCharLeafEnt FcCharLeafEnt; |
931 | | |
932 | | struct _FcCharLeafEnt { |
933 | | FcCharLeafEnt *next; |
934 | | FcChar32 hash; |
935 | | FcCharLeaf leaf; |
936 | | }; |
937 | | |
938 | 2 | #define FC_CHAR_LEAF_BLOCK (4096 / sizeof (FcCharLeafEnt)) |
939 | 275 | #define FC_CHAR_LEAF_HASH_SIZE 257 |
940 | | |
941 | | typedef struct _FcCharSetEnt FcCharSetEnt; |
942 | | |
943 | | struct _FcCharSetEnt { |
944 | | FcCharSetEnt *next; |
945 | | FcChar32 hash; |
946 | | FcCharSet set; |
947 | | }; |
948 | | |
949 | | typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt; |
950 | | |
951 | | struct _FcCharSetOrigEnt { |
952 | | FcCharSetOrigEnt *next; |
953 | | const FcCharSet *orig; |
954 | | const FcCharSet *frozen; |
955 | | }; |
956 | | |
957 | 188 | #define FC_CHAR_SET_HASH_SIZE 67 |
958 | | |
959 | | struct _FcCharSetFreezer { |
960 | | FcCharLeafEnt *leaf_hash_table[FC_CHAR_LEAF_HASH_SIZE]; |
961 | | FcCharLeafEnt **leaf_blocks; |
962 | | int leaf_block_count; |
963 | | FcCharSetEnt *set_hash_table[FC_CHAR_SET_HASH_SIZE]; |
964 | | FcCharSetOrigEnt *orig_hash_table[FC_CHAR_SET_HASH_SIZE]; |
965 | | FcCharLeafEnt *current_block; |
966 | | int leaf_remain; |
967 | | int leaves_seen; |
968 | | int charsets_seen; |
969 | | int leaves_allocated; |
970 | | int charsets_allocated; |
971 | | }; |
972 | | |
973 | | static FcCharLeafEnt * |
974 | | FcCharLeafEntCreate (FcCharSetFreezer *freezer) |
975 | 48 | { |
976 | 48 | if (!freezer->leaf_remain) { |
977 | 1 | FcCharLeafEnt **newBlocks; |
978 | | |
979 | 1 | freezer->leaf_block_count++; |
980 | 1 | newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *)); |
981 | 1 | if (!newBlocks) |
982 | 0 | return 0; |
983 | 1 | freezer->leaf_blocks = newBlocks; |
984 | 1 | freezer->current_block = freezer->leaf_blocks[freezer->leaf_block_count - 1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt)); |
985 | 1 | if (!freezer->current_block) |
986 | 0 | return 0; |
987 | 1 | freezer->leaf_remain = FC_CHAR_LEAF_BLOCK; |
988 | 1 | } |
989 | 48 | freezer->leaf_remain--; |
990 | 48 | freezer->leaves_allocated++; |
991 | 48 | return freezer->current_block++; |
992 | 48 | } |
993 | | |
994 | | static FcChar32 |
995 | | FcCharLeafHash (FcCharLeaf *leaf) |
996 | 550 | { |
997 | 550 | FcChar32 hash = 0; |
998 | 550 | int i; |
999 | | |
1000 | 4.95k | for (i = 0; i < 256 / 32; i++) |
1001 | 4.40k | hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i]; |
1002 | 550 | return hash; |
1003 | 550 | } |
1004 | | |
1005 | | static FcCharLeaf * |
1006 | | FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf) |
1007 | 275 | { |
1008 | 275 | FcChar32 hash = FcCharLeafHash (leaf); |
1009 | 275 | FcCharLeafEnt **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE]; |
1010 | 275 | FcCharLeafEnt *ent; |
1011 | | |
1012 | 308 | for (ent = *bucket; ent; ent = ent->next) { |
1013 | 260 | if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf))) |
1014 | 227 | return &ent->leaf; |
1015 | 260 | } |
1016 | | |
1017 | 48 | ent = FcCharLeafEntCreate (freezer); |
1018 | 48 | if (!ent) |
1019 | 0 | return 0; |
1020 | 48 | ent->leaf = *leaf; |
1021 | 48 | ent->hash = hash; |
1022 | 48 | ent->next = *bucket; |
1023 | 48 | *bucket = ent; |
1024 | 48 | return &ent->leaf; |
1025 | 48 | } |
1026 | | |
1027 | | static FcChar32 |
1028 | | FcCharSetHash (FcCharSet *fcs) |
1029 | 13 | { |
1030 | 13 | FcChar32 hash = 0; |
1031 | 13 | int i; |
1032 | | |
1033 | | /* hash in leaves */ |
1034 | 288 | for (i = 0; i < fcs->num; i++) |
1035 | 275 | hash = ((hash << 1) | (hash >> 31)) ^ FcCharLeafHash (FcCharSetLeaf (fcs, i)); |
1036 | | /* hash in numbers */ |
1037 | 288 | for (i = 0; i < fcs->num; i++) |
1038 | 275 | hash = ((hash << 1) | (hash >> 31)) ^ FcCharSetNumbers (fcs)[i]; |
1039 | 13 | return hash; |
1040 | 13 | } |
1041 | | |
1042 | | static FcBool |
1043 | | FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen) |
1044 | 13 | { |
1045 | 13 | FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t)orig) % FC_CHAR_SET_HASH_SIZE]; |
1046 | 13 | FcCharSetOrigEnt *ent; |
1047 | | |
1048 | 13 | ent = malloc (sizeof (FcCharSetOrigEnt)); |
1049 | 13 | if (!ent) |
1050 | 0 | return FcFalse; |
1051 | 13 | ent->orig = orig; |
1052 | 13 | ent->frozen = frozen; |
1053 | 13 | ent->next = *bucket; |
1054 | 13 | *bucket = ent; |
1055 | 13 | return FcTrue; |
1056 | 13 | } |
1057 | | |
1058 | | static FcCharSet * |
1059 | | FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs) |
1060 | 13 | { |
1061 | 13 | FcChar32 hash = FcCharSetHash (fcs); |
1062 | 13 | FcCharSetEnt **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE]; |
1063 | 13 | FcCharSetEnt *ent; |
1064 | 13 | int size; |
1065 | 13 | int i; |
1066 | | |
1067 | 14 | for (ent = *bucket; ent; ent = ent->next) { |
1068 | 8 | if (ent->hash == hash && |
1069 | 8 | ent->set.num == fcs->num && |
1070 | 8 | !memcmp (FcCharSetNumbers (&ent->set), |
1071 | 7 | FcCharSetNumbers (fcs), |
1072 | 7 | fcs->num * sizeof (FcChar16))) { |
1073 | 7 | FcBool ok = FcTrue; |
1074 | 7 | int i; |
1075 | | |
1076 | 152 | for (i = 0; i < fcs->num; i++) |
1077 | 145 | if (FcCharSetLeaf (&ent->set, i) != FcCharSetLeaf (fcs, i)) |
1078 | 0 | ok = FcFalse; |
1079 | 7 | if (ok) |
1080 | 7 | return &ent->set; |
1081 | 7 | } |
1082 | 8 | } |
1083 | | |
1084 | 6 | size = (sizeof (FcCharSetEnt) + |
1085 | 6 | fcs->num * sizeof (FcCharLeaf *) + |
1086 | 6 | fcs->num * sizeof (FcChar16)); |
1087 | 6 | ent = malloc (size); |
1088 | 6 | if (!ent) |
1089 | 0 | return 0; |
1090 | | |
1091 | 6 | freezer->charsets_allocated++; |
1092 | | |
1093 | 6 | FcRefSetConst (&ent->set.ref); |
1094 | 6 | ent->set.num = fcs->num; |
1095 | 6 | if (fcs->num) { |
1096 | 6 | intptr_t *ent_leaves; |
1097 | | |
1098 | 6 | ent->set.leaves_offset = sizeof (ent->set); |
1099 | 6 | ent->set.numbers_offset = (ent->set.leaves_offset + |
1100 | 6 | fcs->num * sizeof (intptr_t)); |
1101 | | |
1102 | 6 | ent_leaves = FcCharSetLeaves (&ent->set); |
1103 | 136 | for (i = 0; i < fcs->num; i++) |
1104 | 130 | ent_leaves[i] = FcPtrToOffset (ent_leaves, |
1105 | 6 | FcCharSetLeaf (fcs, i)); |
1106 | 6 | memcpy (FcCharSetNumbers (&ent->set), |
1107 | 6 | FcCharSetNumbers (fcs), |
1108 | 6 | fcs->num * sizeof (FcChar16)); |
1109 | 6 | } else { |
1110 | 0 | ent->set.leaves_offset = 0; |
1111 | 0 | ent->set.numbers_offset = 0; |
1112 | 0 | } |
1113 | | |
1114 | 6 | ent->hash = hash; |
1115 | 6 | ent->next = *bucket; |
1116 | 6 | *bucket = ent; |
1117 | | |
1118 | 6 | return &ent->set; |
1119 | 6 | } |
1120 | | |
1121 | | static const FcCharSet * |
1122 | | FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig) |
1123 | 26 | { |
1124 | 26 | FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t)orig) % FC_CHAR_SET_HASH_SIZE]; |
1125 | 26 | FcCharSetOrigEnt *ent; |
1126 | | |
1127 | 28 | for (ent = *bucket; ent; ent = ent->next) |
1128 | 15 | if (ent->orig == orig) |
1129 | 13 | return ent->frozen; |
1130 | 13 | return NULL; |
1131 | 26 | } |
1132 | | |
1133 | | const FcCharSet * |
1134 | | FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs) |
1135 | 13 | { |
1136 | 13 | FcCharSet *b; |
1137 | 13 | const FcCharSet *n = 0; |
1138 | 13 | FcCharLeaf *l; |
1139 | 13 | int i; |
1140 | | |
1141 | 13 | b = FcCharSetCreate(); |
1142 | 13 | if (!b) |
1143 | 0 | goto bail0; |
1144 | 288 | for (i = 0; i < fcs->num; i++) { |
1145 | 275 | l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf (fcs, i)); |
1146 | 275 | if (!l) |
1147 | 0 | goto bail1; |
1148 | 275 | if (!FcCharSetInsertLeaf (b, FcCharSetNumbers (fcs)[i] << 8, l)) |
1149 | 0 | goto bail1; |
1150 | 275 | } |
1151 | 13 | n = FcCharSetFreezeBase (freezer, b); |
1152 | 13 | if (!FcCharSetFreezeOrig (freezer, fcs, n)) { |
1153 | 0 | n = NULL; |
1154 | 0 | goto bail1; |
1155 | 0 | } |
1156 | 13 | freezer->charsets_seen++; |
1157 | 13 | freezer->leaves_seen += fcs->num; |
1158 | 13 | bail1: |
1159 | 13 | if (b->num) |
1160 | 13 | free (FcCharSetLeaves (b)); |
1161 | 13 | if (b->num) |
1162 | 13 | free (FcCharSetNumbers (b)); |
1163 | 13 | free (b); |
1164 | 13 | bail0: |
1165 | 13 | return n; |
1166 | 13 | } |
1167 | | |
1168 | | FcCharSetFreezer * |
1169 | | FcCharSetFreezerCreate (void) |
1170 | 1 | { |
1171 | 1 | FcCharSetFreezer *freezer; |
1172 | | |
1173 | 1 | freezer = calloc (1, sizeof (FcCharSetFreezer)); |
1174 | 1 | return freezer; |
1175 | 1 | } |
1176 | | |
1177 | | void |
1178 | | FcCharSetFreezerDestroy (FcCharSetFreezer *freezer) |
1179 | 1 | { |
1180 | 1 | int i; |
1181 | | |
1182 | 1 | if (FcDebug() & FC_DBG_CACHE) { |
1183 | 0 | printf ("\ncharsets %d -> %d leaves %d -> %d\n", |
1184 | 0 | freezer->charsets_seen, freezer->charsets_allocated, |
1185 | 0 | freezer->leaves_seen, freezer->leaves_allocated); |
1186 | 0 | } |
1187 | 68 | for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++) { |
1188 | 67 | FcCharSetEnt *ent, *next; |
1189 | 73 | for (ent = freezer->set_hash_table[i]; ent; ent = next) { |
1190 | 6 | next = ent->next; |
1191 | 6 | free (ent); |
1192 | 6 | } |
1193 | 67 | } |
1194 | | |
1195 | 68 | for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++) { |
1196 | 67 | FcCharSetOrigEnt *ent, *next; |
1197 | 80 | for (ent = freezer->orig_hash_table[i]; ent; ent = next) { |
1198 | 13 | next = ent->next; |
1199 | 13 | free (ent); |
1200 | 13 | } |
1201 | 67 | } |
1202 | | |
1203 | 2 | for (i = 0; i < freezer->leaf_block_count; i++) |
1204 | 1 | free (freezer->leaf_blocks[i]); |
1205 | | |
1206 | 1 | free (freezer->leaf_blocks); |
1207 | 1 | free (freezer); |
1208 | 1 | } |
1209 | | |
1210 | | FcBool |
1211 | | FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs) |
1212 | 13 | { |
1213 | 13 | intptr_t *leaves; |
1214 | 13 | FcChar16 *numbers; |
1215 | 13 | int i; |
1216 | | |
1217 | 13 | if (!FcRefIsConst (&cs->ref)) { |
1218 | 13 | if (!serialize->cs_freezer) { |
1219 | 1 | serialize->cs_freezer = FcCharSetFreezerCreate(); |
1220 | 1 | if (!serialize->cs_freezer) |
1221 | 0 | return FcFalse; |
1222 | 1 | } |
1223 | 13 | if (FcCharSetFindFrozen (serialize->cs_freezer, cs)) |
1224 | 0 | return FcTrue; |
1225 | | |
1226 | 13 | cs = FcCharSetFreeze (serialize->cs_freezer, cs); |
1227 | 13 | } |
1228 | | |
1229 | 13 | leaves = FcCharSetLeaves (cs); |
1230 | 13 | numbers = FcCharSetNumbers (cs); |
1231 | | |
1232 | 13 | if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet))) |
1233 | 0 | return FcFalse; |
1234 | 13 | if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t))) |
1235 | 0 | return FcFalse; |
1236 | 13 | if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16))) |
1237 | 0 | return FcFalse; |
1238 | 288 | for (i = 0; i < cs->num; i++) |
1239 | 275 | if (!FcSerializeAlloc (serialize, FcCharSetLeaf (cs, i), |
1240 | 275 | sizeof (FcCharLeaf))) |
1241 | 0 | return FcFalse; |
1242 | 13 | return FcTrue; |
1243 | 13 | } |
1244 | | |
1245 | | FcCharSet * |
1246 | | FcCharSetSerialize (FcSerialize *serialize, const FcCharSet *cs) |
1247 | 13 | { |
1248 | 13 | FcCharSet *cs_serialized; |
1249 | 13 | intptr_t *leaves, *leaves_serialized; |
1250 | 13 | FcChar16 *numbers, *numbers_serialized; |
1251 | 13 | FcCharLeaf *leaf, *leaf_serialized; |
1252 | 13 | int i; |
1253 | | |
1254 | 13 | if (!FcRefIsConst (&cs->ref) && serialize->cs_freezer) { |
1255 | 13 | cs = FcCharSetFindFrozen (serialize->cs_freezer, cs); |
1256 | 13 | if (!cs) |
1257 | 0 | return NULL; |
1258 | 13 | } |
1259 | | |
1260 | 13 | cs_serialized = FcSerializePtr (serialize, cs); |
1261 | 13 | if (!cs_serialized) |
1262 | 0 | return NULL; |
1263 | | |
1264 | 13 | FcRefSetConst (&cs_serialized->ref); |
1265 | 13 | cs_serialized->num = cs->num; |
1266 | | |
1267 | 13 | if (cs->num) { |
1268 | 13 | leaves = FcCharSetLeaves (cs); |
1269 | 13 | leaves_serialized = FcSerializePtr (serialize, leaves); |
1270 | 13 | if (!leaves_serialized) |
1271 | 0 | return NULL; |
1272 | | |
1273 | 13 | cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized, |
1274 | 13 | leaves_serialized); |
1275 | | |
1276 | 13 | numbers = FcCharSetNumbers (cs); |
1277 | 13 | numbers_serialized = FcSerializePtr (serialize, numbers); |
1278 | 13 | if (!numbers) |
1279 | 0 | return NULL; |
1280 | | |
1281 | 13 | cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized, |
1282 | 13 | numbers_serialized); |
1283 | | |
1284 | 288 | for (i = 0; i < cs->num; i++) { |
1285 | 275 | leaf = FcCharSetLeaf (cs, i); |
1286 | 275 | leaf_serialized = FcSerializePtr (serialize, leaf); |
1287 | 275 | if (!leaf_serialized) |
1288 | 0 | return NULL; |
1289 | 275 | *leaf_serialized = *leaf; |
1290 | 275 | leaves_serialized[i] = FcPtrToOffset (leaves_serialized, |
1291 | 275 | leaf_serialized); |
1292 | 275 | numbers_serialized[i] = numbers[i]; |
1293 | 275 | } |
1294 | 13 | } else { |
1295 | 0 | cs_serialized->leaves_offset = 0; |
1296 | 0 | cs_serialized->numbers_offset = 0; |
1297 | 0 | } |
1298 | | |
1299 | 13 | return cs_serialized; |
1300 | 13 | } |
1301 | | #define __fccharset__ |
1302 | | #include "fcaliastail.h" |
1303 | | #undef __fccharset__ |