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