Coverage Report

Created: 2026-05-16 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fontconfig/src/fcserialize.c
Line
Count
Source
1
/*
2
 * Copyright © 2006 Keith Packard
3
 *
4
 * Permission to use, copy, modify, distribute, and sell this software and its
5
 * documentation for any purpose is hereby granted without fee, provided that
6
 * the above copyright notice appear in all copies and that both that copyright
7
 * notice and this permission notice appear in supporting documentation, and
8
 * that the name of the copyright holders not be used in advertising or
9
 * publicity pertaining to distribution of the software without specific,
10
 * written prior permission.  The copyright holders make no representations
11
 * about the suitability of this software for any purpose.  It is provided "as
12
 * is" without express or implied warranty.
13
 *
14
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20
 * OF THIS SOFTWARE.
21
 */
22
23
#include "fcint.h"
24
25
intptr_t
26
FcAlignSize (intptr_t size)
27
0
{
28
0
    intptr_t rem = size % sizeof (FcAlign);
29
0
    if (rem)
30
0
  size += sizeof (FcAlign) - rem;
31
0
    return size;
32
0
}
33
34
/*
35
 * Serialization helper object -- allocate space in the
36
 * yet-to-be-created linear array for a serialized font set
37
 */
38
39
FcSerialize *
40
FcSerializeCreate (void)
41
0
{
42
0
    FcSerialize *serialize;
43
44
0
    serialize = malloc (sizeof (FcSerialize));
45
0
    if (!serialize)
46
0
  return NULL;
47
0
    serialize->size = 0;
48
0
    serialize->linear = NULL;
49
0
    serialize->cs_freezer = NULL;
50
0
    serialize->buckets = NULL;
51
0
    serialize->buckets_count = 0;
52
0
    serialize->buckets_used = 0;
53
0
    serialize->buckets_used_max = 0;
54
0
    return serialize;
55
0
}
56
57
void
58
FcSerializeDestroy (FcSerialize *serialize)
59
0
{
60
0
    free (serialize->buckets);
61
0
    if (serialize->cs_freezer)
62
0
  FcCharSetFreezerDestroy (serialize->cs_freezer);
63
0
    free (serialize);
64
0
}
65
66
static size_t
67
FcSerializeNextBucketIndex (const FcSerialize *serialize, size_t index)
68
0
{
69
0
    if (index == 0)
70
0
  index = serialize->buckets_count;
71
0
    --index;
72
0
    return index;
73
0
}
74
75
#if ((SIZEOF_VOID_P) * (CHAR_BIT)) == 32
76
77
/*
78
 * Based on triple32
79
 * https://github.com/skeeto/hash-prospector
80
 */
81
static uintptr_t
82
FcSerializeHashPtr (const void *object)
83
{
84
    uintptr_t x = (uintptr_t)object;
85
    x ^= x >> 17;
86
    x *= 0xed5ad4bbU;
87
    x ^= x >> 11;
88
    x *= 0xac4c1b51U;
89
    x ^= x >> 15;
90
    x *= 0x31848babU;
91
    x ^= x >> 14;
92
    return x ? x : 1; /* 0 reserved to mark empty, x starts out 0 */
93
}
94
95
#elif ((SIZEOF_VOID_P) * (CHAR_BIT)) == 64
96
97
/*
98
 * Based on splittable64/splitmix64 from Mix13
99
 * https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
100
 * https://prng.di.unimi.it/splitmix64.c
101
 */
102
static uintptr_t
103
FcSerializeHashPtr (const void *object)
104
0
{
105
0
    uintptr_t x = (uintptr_t)object;
106
0
    x ^= x >> 30;
107
0
    x *= 0xbf58476d1ce4e5b9U;
108
0
    x ^= x >> 27;
109
0
    x *= 0x94d049bb133111ebU;
110
0
    x ^= x >> 31;
111
0
    return x ? x : 1; /* 0 reserved to mark empty, x starts out 0 */
112
0
}
113
114
#endif
115
116
static FcSerializeBucket *
117
FcSerializeFind (const FcSerialize *serialize, const void *object)
118
0
{
119
0
    uintptr_t hash = FcSerializeHashPtr (object);
120
0
    size_t    buckets_count = serialize->buckets_count;
121
0
    size_t    index = hash & (buckets_count - 1);
122
0
    for (size_t n = 0; n < buckets_count; ++n) {
123
0
  FcSerializeBucket *bucket = &serialize->buckets[index];
124
0
  if (bucket->hash == 0) {
125
0
      return NULL;
126
0
  }
127
0
  if (object == bucket->object) {
128
0
      return bucket;
129
0
  }
130
0
  index = FcSerializeNextBucketIndex (serialize, index);
131
0
    }
132
0
    return NULL;
133
0
}
134
135
static FcSerializeBucket *
136
FcSerializeUncheckedSet (FcSerialize *serialize, FcSerializeBucket *insert)
137
0
{
138
0
    const void *object = insert->object;
139
0
    size_t      buckets_count = serialize->buckets_count;
140
0
    size_t      index = insert->hash & (buckets_count - 1);
141
0
    for (size_t n = 0; n < buckets_count; ++n) {
142
0
  FcSerializeBucket *bucket = &serialize->buckets[index];
143
0
  if (bucket->hash == 0) {
144
0
      *bucket = *insert;
145
0
      ++serialize->buckets_used;
146
0
      return bucket;
147
0
  }
148
0
  if (object == bucket->object) {
149
      /* FcSerializeAlloc should not allow this to happen. */
150
0
      assert (0);
151
0
      *bucket = *insert;
152
0
      return bucket;
153
0
  }
154
0
  index = FcSerializeNextBucketIndex (serialize, index);
155
0
    }
156
0
    assert (0);
157
0
    return NULL;
158
0
}
159
160
static FcBool
161
FcSerializeResize (FcSerialize *serialize, size_t new_count)
162
0
{
163
0
    size_t             old_used = serialize->buckets_used;
164
0
    size_t             old_count = serialize->buckets_count;
165
0
    FcSerializeBucket *old_buckets = serialize->buckets;
166
0
    FcSerializeBucket *old_buckets_end = old_buckets ? old_buckets + old_count : NULL;
167
168
0
    FcSerializeBucket *new_buckets = malloc (new_count * sizeof (*old_buckets));
169
0
    if (!new_buckets)
170
0
  return FcFalse;
171
0
    FcSerializeBucket *new_buckets_end = new_buckets + new_count;
172
0
    for (FcSerializeBucket *b = new_buckets; b < new_buckets_end; ++b)
173
0
  b->hash = 0;
174
175
0
    serialize->buckets = new_buckets;
176
0
    serialize->buckets_count = new_count;
177
0
    serialize->buckets_used = 0;
178
0
    for (FcSerializeBucket *b = old_buckets; b < old_buckets_end; ++b)
179
0
  if (b->hash != 0 && !FcSerializeUncheckedSet (serialize, b)) {
180
0
      serialize->buckets = old_buckets;
181
0
      serialize->buckets_count = old_count;
182
0
      serialize->buckets_used = old_used;
183
0
      free (new_buckets);
184
0
      return FcFalse;
185
0
  }
186
0
    free (old_buckets);
187
0
    return FcTrue;
188
0
}
189
190
static FcSerializeBucket *
191
FcSerializeSet (FcSerialize *serialize, const void *object, intptr_t offset)
192
0
{
193
0
    if (serialize->buckets_used >= serialize->buckets_used_max) {
194
0
  size_t capacity = serialize->buckets_count;
195
0
  if (capacity == 0)
196
0
      capacity = 4;
197
0
  else if (capacity > SIZE_MAX / 2u)
198
0
      return NULL;
199
0
  else
200
0
      capacity *= 2;
201
202
0
  if (!FcSerializeResize (serialize, capacity))
203
0
      return NULL;
204
205
0
  serialize->buckets_used_max = capacity / 4u * 3u;
206
0
    }
207
208
0
    FcSerializeBucket bucket;
209
0
    bucket.object = object;
210
0
    bucket.offset = offset;
211
0
    bucket.hash = FcSerializeHashPtr (object);
212
0
    return FcSerializeUncheckedSet (serialize, &bucket);
213
0
}
214
215
/*
216
 * Allocate space for an object in the serialized array. Keep track
217
 * of where the object is placed and only allocate one copy of each object
218
 */
219
FcBool
220
FcSerializeAlloc (FcSerialize *serialize, const void *object, int size)
221
0
{
222
0
    FcSerializeBucket *bucket = FcSerializeFind (serialize, object);
223
0
    if (bucket)
224
0
  return FcTrue;
225
226
0
    if (!FcSerializeSet (serialize, object, serialize->size))
227
0
  return FcFalse;
228
229
0
    serialize->size += FcAlignSize (size);
230
0
    return FcTrue;
231
0
}
232
233
/*
234
 * Reserve space in the serialization array
235
 */
236
intptr_t
237
FcSerializeReserve (FcSerialize *serialize, int size)
238
0
{
239
0
    intptr_t offset = serialize->size;
240
0
    serialize->size += FcAlignSize (size);
241
0
    return offset;
242
0
}
243
244
/*
245
 * Given an object, return the offset in the serialized array where
246
 * the serialized copy of the object is stored
247
 */
248
intptr_t
249
FcSerializeOffset (FcSerialize *serialize, const void *object)
250
0
{
251
0
    FcSerializeBucket *bucket = FcSerializeFind (serialize, object);
252
0
    return bucket ? bucket->offset : 0;
253
0
}
254
255
/*
256
 * Given a cache and an object, return a pointer to where
257
 * the serialized copy of the object is stored
258
 */
259
void *
260
FcSerializePtr (FcSerialize *serialize, const void *object)
261
0
{
262
0
    intptr_t offset = FcSerializeOffset (serialize, object);
263
264
0
    if (!offset)
265
0
  return NULL;
266
0
    return (void *)((char *)serialize->linear + offset);
267
0
}
268
269
FcBool
270
FcStrSerializeAlloc (FcSerialize *serialize, const FcChar8 *str)
271
0
{
272
0
    return FcSerializeAlloc (serialize, str, strlen ((const char *)str) + 1);
273
0
}
274
275
FcChar8 *
276
FcStrSerialize (FcSerialize *serialize, const FcChar8 *str)
277
0
{
278
0
    FcChar8 *str_serialize = FcSerializePtr (serialize, str);
279
0
    if (!str_serialize)
280
0
  return NULL;
281
0
    strcpy ((char *)str_serialize, (const char *)str);
282
0
    return str_serialize;
283
0
}
284
#include "fcaliastail.h"
285
#undef __fcserialize__