1/****************************************************************************
2 *
3 * ftutil.c
4 *
5 * FreeType utility file for memory and list management (body).
6 *
7 * Copyright (C) 2002-2023 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
9 *
10 * This file is part of the FreeType project, and may only be used,
11 * modified, and distributed under the terms of the FreeType project
12 * license, LICENSE.TXT. By continuing to use, modify, or distribute
13 * this file you indicate that you have read the license and
14 * understand and accept it fully.
15 *
16 */
17
18
19#include <freetype/internal/ftdebug.h>
20#include <freetype/internal/ftmemory.h>
21#include <freetype/internal/ftobjs.h>
22#include <freetype/ftlist.h>
23
24
25 /**************************************************************************
26 *
27 * The macro FT_COMPONENT is used in trace mode. It is an implicit
28 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
29 * messages during execution.
30 */
31#undef FT_COMPONENT
32#define FT_COMPONENT memory
33
34
35 /*************************************************************************/
36 /*************************************************************************/
37 /*************************************************************************/
38 /***** *****/
39 /***** *****/
40 /***** M E M O R Y M A N A G E M E N T *****/
41 /***** *****/
42 /***** *****/
43 /*************************************************************************/
44 /*************************************************************************/
45 /*************************************************************************/
46
47
48 FT_BASE_DEF( FT_Pointer )
49 ft_mem_alloc( FT_Memory memory,
50 FT_Long size,
51 FT_Error *p_error )
52 {
53 FT_Error error;
54 FT_Pointer block = ft_mem_qalloc( memory, size, &error );
55
56 if ( !error && block && size > 0 )
57 FT_MEM_ZERO( block, size );
58
59 *p_error = error;
60 return block;
61 }
62
63
64 FT_BASE_DEF( FT_Pointer )
65 ft_mem_qalloc( FT_Memory memory,
66 FT_Long size,
67 FT_Error *p_error )
68 {
69 FT_Error error = FT_Err_Ok;
70 FT_Pointer block = NULL;
71
72
73 if ( size > 0 )
74 {
75 block = memory->alloc( memory, size );
76 if ( !block )
77 error = FT_THROW( Out_Of_Memory );
78 }
79 else if ( size < 0 )
80 {
81 /* may help catch/prevent security issues */
82 error = FT_THROW( Invalid_Argument );
83 }
84
85 *p_error = error;
86 return block;
87 }
88
89
90 FT_BASE_DEF( FT_Pointer )
91 ft_mem_realloc( FT_Memory memory,
92 FT_Long item_size,
93 FT_Long cur_count,
94 FT_Long new_count,
95 void* block,
96 FT_Error *p_error )
97 {
98 FT_Error error = FT_Err_Ok;
99
100
101 block = ft_mem_qrealloc( memory, item_size,
102 cur_count, new_count, block, &error );
103 if ( !error && block && new_count > cur_count )
104 FT_MEM_ZERO( (char*)block + cur_count * item_size,
105 ( new_count - cur_count ) * item_size );
106
107 *p_error = error;
108 return block;
109 }
110
111
112 FT_BASE_DEF( FT_Pointer )
113 ft_mem_qrealloc( FT_Memory memory,
114 FT_Long item_size,
115 FT_Long cur_count,
116 FT_Long new_count,
117 void* block,
118 FT_Error *p_error )
119 {
120 FT_Error error = FT_Err_Ok;
121
122
123 /* Note that we now accept `item_size == 0' as a valid parameter, in
124 * order to cover very weird cases where an ALLOC_MULT macro would be
125 * called.
126 */
127 if ( cur_count < 0 || new_count < 0 || item_size < 0 )
128 {
129 /* may help catch/prevent nasty security issues */
130 error = FT_THROW( Invalid_Argument );
131 }
132 else if ( new_count == 0 || item_size == 0 )
133 {
134 ft_mem_free( memory, block );
135 block = NULL;
136 }
137 else if ( new_count > FT_INT_MAX / item_size )
138 {
139 error = FT_THROW( Array_Too_Large );
140 }
141 else if ( cur_count == 0 )
142 {
143 FT_ASSERT( !block );
144
145 block = memory->alloc( memory, new_count * item_size );
146 if ( block == NULL )
147 error = FT_THROW( Out_Of_Memory );
148 }
149 else
150 {
151 FT_Pointer block2;
152 FT_Long cur_size = cur_count * item_size;
153 FT_Long new_size = new_count * item_size;
154
155
156 block2 = memory->realloc( memory, cur_size, new_size, block );
157 if ( !block2 )
158 error = FT_THROW( Out_Of_Memory );
159 else
160 block = block2;
161 }
162
163 *p_error = error;
164 return block;
165 }
166
167
168 FT_BASE_DEF( void )
169 ft_mem_free( FT_Memory memory,
170 const void *P )
171 {
172 if ( P )
173 memory->free( memory, (void*)P );
174 }
175
176
177 FT_BASE_DEF( FT_Pointer )
178 ft_mem_dup( FT_Memory memory,
179 const void* address,
180 FT_ULong size,
181 FT_Error *p_error )
182 {
183 FT_Error error;
184 FT_Pointer p = ft_mem_qalloc( memory, (FT_Long)size, &error );
185
186
187 if ( !error && address && size > 0 )
188 ft_memcpy( p, address, size );
189
190 *p_error = error;
191 return p;
192 }
193
194
195 FT_BASE_DEF( FT_Pointer )
196 ft_mem_strdup( FT_Memory memory,
197 const char* str,
198 FT_Error *p_error )
199 {
200 FT_ULong len = str ? (FT_ULong)ft_strlen( str ) + 1
201 : 0;
202
203
204 return ft_mem_dup( memory, str, len, p_error );
205 }
206
207
208 FT_BASE_DEF( FT_Int )
209 ft_mem_strcpyn( char* dst,
210 const char* src,
211 FT_ULong size )
212 {
213 while ( size > 1 && *src != 0 )
214 {
215 *dst++ = *src++;
216 size--;
217 }
218
219 *dst = 0; /* always zero-terminate */
220
221 return *src != 0;
222 }
223
224
225 /*************************************************************************/
226 /*************************************************************************/
227 /*************************************************************************/
228 /***** *****/
229 /***** *****/
230 /***** D O U B L Y L I N K E D L I S T S *****/
231 /***** *****/
232 /***** *****/
233 /*************************************************************************/
234 /*************************************************************************/
235 /*************************************************************************/
236
237#undef FT_COMPONENT
238#define FT_COMPONENT list
239
240 /* documentation is in ftlist.h */
241
242 FT_EXPORT_DEF( FT_ListNode )
243 FT_List_Find( FT_List list,
244 void* data )
245 {
246 FT_ListNode cur;
247
248
249 if ( !list )
250 return NULL;
251
252 cur = list->head;
253 while ( cur )
254 {
255 if ( cur->data == data )
256 return cur;
257
258 cur = cur->next;
259 }
260
261 return NULL;
262 }
263
264
265 /* documentation is in ftlist.h */
266
267 FT_EXPORT_DEF( void )
268 FT_List_Add( FT_List list,
269 FT_ListNode node )
270 {
271 FT_ListNode before;
272
273
274 if ( !list || !node )
275 return;
276
277 before = list->tail;
278
279 node->next = NULL;
280 node->prev = before;
281
282 if ( before )
283 before->next = node;
284 else
285 list->head = node;
286
287 list->tail = node;
288 }
289
290
291 /* documentation is in ftlist.h */
292
293 FT_EXPORT_DEF( void )
294 FT_List_Insert( FT_List list,
295 FT_ListNode node )
296 {
297 FT_ListNode after;
298
299
300 if ( !list || !node )
301 return;
302
303 after = list->head;
304
305 node->next = after;
306 node->prev = NULL;
307
308 if ( !after )
309 list->tail = node;
310 else
311 after->prev = node;
312
313 list->head = node;
314 }
315
316
317 /* documentation is in ftlist.h */
318
319 FT_EXPORT_DEF( void )
320 FT_List_Remove( FT_List list,
321 FT_ListNode node )
322 {
323 FT_ListNode before, after;
324
325
326 if ( !list || !node )
327 return;
328
329 before = node->prev;
330 after = node->next;
331
332 if ( before )
333 before->next = after;
334 else
335 list->head = after;
336
337 if ( after )
338 after->prev = before;
339 else
340 list->tail = before;
341 }
342
343
344 /* documentation is in ftlist.h */
345
346 FT_EXPORT_DEF( void )
347 FT_List_Up( FT_List list,
348 FT_ListNode node )
349 {
350 FT_ListNode before, after;
351
352
353 if ( !list || !node )
354 return;
355
356 before = node->prev;
357 after = node->next;
358
359 /* check whether we are already on top of the list */
360 if ( !before )
361 return;
362
363 before->next = after;
364
365 if ( after )
366 after->prev = before;
367 else
368 list->tail = before;
369
370 node->prev = NULL;
371 node->next = list->head;
372 list->head->prev = node;
373 list->head = node;
374 }
375
376
377 /* documentation is in ftlist.h */
378
379 FT_EXPORT_DEF( FT_Error )
380 FT_List_Iterate( FT_List list,
381 FT_List_Iterator iterator,
382 void* user )
383 {
384 FT_ListNode cur;
385 FT_Error error = FT_Err_Ok;
386
387
388 if ( !list || !iterator )
389 return FT_THROW( Invalid_Argument );
390
391 cur = list->head;
392
393 while ( cur )
394 {
395 FT_ListNode next = cur->next;
396
397
398 error = iterator( cur, user );
399 if ( error )
400 break;
401
402 cur = next;
403 }
404
405 return error;
406 }
407
408
409 /* documentation is in ftlist.h */
410
411 FT_EXPORT_DEF( void )
412 FT_List_Finalize( FT_List list,
413 FT_List_Destructor destroy,
414 FT_Memory memory,
415 void* user )
416 {
417 FT_ListNode cur;
418
419
420 if ( !list || !memory )
421 return;
422
423 cur = list->head;
424 while ( cur )
425 {
426 FT_ListNode next = cur->next;
427 void* data = cur->data;
428
429
430 if ( destroy )
431 destroy( memory, data, user );
432
433 FT_FREE( cur );
434 cur = next;
435 }
436
437 list->head = NULL;
438 list->tail = NULL;
439 }
440
441
442/* END */
443