1/***************************************************************************/
2/*                                                                         */
3/*  ftutil.c                                                               */
4/*                                                                         */
5/*    FreeType utility file for memory and list management (body).         */
6/*                                                                         */
7/*  Copyright 2002, 2004-2007, 2013 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 == NULL )
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 == NULL );
145
146      block = ft_mem_alloc( memory, new_count*item_size, &error );
147    }
148    else
149    {
150      FT_Pointer  block2;
151      FT_Long     cur_size = cur_count*item_size;
152      FT_Long     new_size = new_count*item_size;
153
154
155      block2 = memory->realloc( memory, cur_size, new_size, block );
156      if ( block2 == NULL )
157        error = FT_THROW( Out_Of_Memory );
158      else
159        block = block2;
160    }
161
162    *p_error = error;
163    return block;
164  }
165
166
167  FT_BASE_DEF( void )
168  ft_mem_free( FT_Memory   memory,
169               const void *P )
170  {
171    if ( P )
172      memory->free( memory, (void*)P );
173  }
174
175
176  FT_BASE_DEF( FT_Pointer )
177  ft_mem_dup( FT_Memory    memory,
178              const void*  address,
179              FT_ULong     size,
180              FT_Error    *p_error )
181  {
182    FT_Error    error;
183    FT_Pointer  p = ft_mem_qalloc( memory, size, &error );
184
185
186    if ( !error && address )
187      ft_memcpy( p, address, size );
188
189    *p_error = error;
190    return p;
191  }
192
193
194  FT_BASE_DEF( FT_Pointer )
195  ft_mem_strdup( FT_Memory    memory,
196                 const char*  str,
197                 FT_Error    *p_error )
198  {
199    FT_ULong  len = str ? (FT_ULong)ft_strlen( str ) + 1
200                        : 0;
201
202
203    return ft_mem_dup( memory, str, len, p_error );
204  }
205
206
207  FT_BASE_DEF( FT_Int )
208  ft_mem_strcpyn( char*        dst,
209                  const char*  src,
210                  FT_ULong     size )
211  {
212    while ( size > 1 && *src != 0 )
213    {
214      *dst++ = *src++;
215      size--;
216    }
217
218    *dst = 0;  /* always zero-terminate */
219
220    return *src != 0;
221  }
222
223
224  /*************************************************************************/
225  /*************************************************************************/
226  /*************************************************************************/
227  /*****                                                               *****/
228  /*****                                                               *****/
229  /*****            D O U B L Y   L I N K E D   L I S T S              *****/
230  /*****                                                               *****/
231  /*****                                                               *****/
232  /*************************************************************************/
233  /*************************************************************************/
234  /*************************************************************************/
235
236#undef  FT_COMPONENT
237#define FT_COMPONENT  trace_list
238
239  /* documentation is in ftlist.h */
240
241  FT_EXPORT_DEF( FT_ListNode )
242  FT_List_Find( FT_List  list,
243                void*    data )
244  {
245    FT_ListNode  cur;
246
247
248    cur = list->head;
249    while ( cur )
250    {
251      if ( cur->data == data )
252        return cur;
253
254      cur = cur->next;
255    }
256
257    return (FT_ListNode)0;
258  }
259
260
261  /* documentation is in ftlist.h */
262
263  FT_EXPORT_DEF( void )
264  FT_List_Add( FT_List      list,
265               FT_ListNode  node )
266  {
267    FT_ListNode  before = list->tail;
268
269
270    node->next = 0;
271    node->prev = before;
272
273    if ( before )
274      before->next = node;
275    else
276      list->head = node;
277
278    list->tail = node;
279  }
280
281
282  /* documentation is in ftlist.h */
283
284  FT_EXPORT_DEF( void )
285  FT_List_Insert( FT_List      list,
286                  FT_ListNode  node )
287  {
288    FT_ListNode  after = list->head;
289
290
291    node->next = after;
292    node->prev = 0;
293
294    if ( !after )
295      list->tail = node;
296    else
297      after->prev = node;
298
299    list->head = node;
300  }
301
302
303  /* documentation is in ftlist.h */
304
305  FT_EXPORT_DEF( void )
306  FT_List_Remove( FT_List      list,
307                  FT_ListNode  node )
308  {
309    FT_ListNode  before, after;
310
311
312    before = node->prev;
313    after  = node->next;
314
315    if ( before )
316      before->next = after;
317    else
318      list->head = after;
319
320    if ( after )
321      after->prev = before;
322    else
323      list->tail = before;
324  }
325
326
327  /* documentation is in ftlist.h */
328
329  FT_EXPORT_DEF( void )
330  FT_List_Up( FT_List      list,
331              FT_ListNode  node )
332  {
333    FT_ListNode  before, after;
334
335
336    before = node->prev;
337    after  = node->next;
338
339    /* check whether we are already on top of the list */
340    if ( !before )
341      return;
342
343    before->next = after;
344
345    if ( after )
346      after->prev = before;
347    else
348      list->tail = before;
349
350    node->prev       = 0;
351    node->next       = list->head;
352    list->head->prev = node;
353    list->head       = node;
354  }
355
356
357  /* documentation is in ftlist.h */
358
359  FT_EXPORT_DEF( FT_Error )
360  FT_List_Iterate( FT_List            list,
361                   FT_List_Iterator   iterator,
362                   void*              user )
363  {
364    FT_ListNode  cur   = list->head;
365    FT_Error     error = FT_Err_Ok;
366
367
368    while ( cur )
369    {
370      FT_ListNode  next = cur->next;
371
372
373      error = iterator( cur, user );
374      if ( error )
375        break;
376
377      cur = next;
378    }
379
380    return error;
381  }
382
383
384  /* documentation is in ftlist.h */
385
386  FT_EXPORT_DEF( void )
387  FT_List_Finalize( FT_List             list,
388                    FT_List_Destructor  destroy,
389                    FT_Memory           memory,
390                    void*               user )
391  {
392    FT_ListNode  cur;
393
394
395    cur = list->head;
396    while ( cur )
397    {
398      FT_ListNode  next = cur->next;
399      void*        data = cur->data;
400
401
402      if ( destroy )
403        destroy( memory, data, user );
404
405      FT_FREE( cur );
406      cur = next;
407    }
408
409    list->head = 0;
410    list->tail = 0;
411  }
412
413
414  FT_BASE_DEF( FT_UInt32 )
415  ft_highpow2( FT_UInt32  value )
416  {
417    FT_UInt32  value2;
418
419
420    /*
421     *  We simply clear the lowest bit in each iteration.  When
422     *  we reach 0, we know that the previous value was our result.
423     */
424    for ( ;; )
425    {
426      value2 = value & (value - 1);  /* clear lowest bit */
427      if ( value2 == 0 )
428        break;
429
430      value = value2;
431    }
432    return value;
433  }
434
435
436/* END */
437