1 /****************************************************************************
2  *
3  * ftutil.c
4  *
5  *   FreeType utility file for memory and list management (body).
6  *
7  * Copyright (C) 2002-2020 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 )
ft_mem_alloc(FT_Memory memory,FT_Long size,FT_Error * p_error)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 )
ft_mem_qalloc(FT_Memory memory,FT_Long size,FT_Error * p_error)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 )
ft_mem_realloc(FT_Memory memory,FT_Long item_size,FT_Long cur_count,FT_Long new_count,void * block,FT_Error * p_error)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 )
ft_mem_qrealloc(FT_Memory memory,FT_Long item_size,FT_Long cur_count,FT_Long new_count,void * block,FT_Error * p_error)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 )
ft_mem_free(FT_Memory memory,const void * P)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 )
ft_mem_dup(FT_Memory memory,const void * address,FT_ULong size,FT_Error * p_error)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 )
ft_mem_strdup(FT_Memory memory,const char * str,FT_Error * p_error)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 )
ft_mem_strcpyn(char * dst,const char * src,FT_ULong size)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 )
FT_List_Find(FT_List list,void * data)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 )
FT_List_Add(FT_List list,FT_ListNode node)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 )
FT_List_Insert(FT_List list,FT_ListNode node)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 )
FT_List_Remove(FT_List list,FT_ListNode node)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 )
FT_List_Up(FT_List list,FT_ListNode node)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 )
FT_List_Iterate(FT_List list,FT_List_Iterator iterator,void * user)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 )
FT_List_Finalize(FT_List list,FT_List_Destructor destroy,FT_Memory memory,void * user)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