1 /****************************************************************************
2  *
3  * ftutil.c
4  *
5  *   FreeType utility file for memory and list management (body).
6  *
7  * Copyright (C) 2002-2019 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  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 )
ft_mem_alloc(FT_Memory memory,FT_Long size,FT_Error * p_error)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 && block && 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 )
ft_mem_qalloc(FT_Memory memory,FT_Long size,FT_Error * p_error)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 )
ft_mem_realloc(FT_Memory memory,FT_Long item_size,FT_Long cur_count,FT_Long new_count,void * block,FT_Error * p_error)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 && block && 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 )
ft_mem_qrealloc(FT_Memory memory,FT_Long item_size,FT_Long cur_count,FT_Long new_count,void * block,FT_Error * p_error)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 )
ft_mem_free(FT_Memory memory,const void * P)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 )
ft_mem_dup(FT_Memory memory,const void * address,FT_ULong size,FT_Error * p_error)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 && size > 0 )
189       ft_memcpy( p, address, size );
190 
191     *p_error = error;
192     return p;
193   }
194 
195 
196   FT_BASE_DEF( FT_Pointer )
ft_mem_strdup(FT_Memory memory,const char * str,FT_Error * p_error)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 )
ft_mem_strcpyn(char * dst,const char * src,FT_ULong size)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  list
240 
241   /* documentation is in ftlist.h */
242 
243   FT_EXPORT_DEF( FT_ListNode )
FT_List_Find(FT_List list,void * data)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 )
FT_List_Add(FT_List list,FT_ListNode node)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 )
FT_List_Insert(FT_List list,FT_ListNode node)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 )
FT_List_Remove(FT_List list,FT_ListNode node)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 )
FT_List_Up(FT_List list,FT_ListNode node)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 )
FT_List_Iterate(FT_List list,FT_List_Iterator iterator,void * user)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 )
FT_List_Finalize(FT_List list,FT_List_Destructor destroy,FT_Memory memory,void * user)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