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