ftutil.c revision ee451cb395940862dad63c85adfe8f2fd55e864c
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 "../../include/ft2build.h"
20#include "../../include/freetype/internal/ftdebug.h"
21#include "../../include/freetype/internal/ftmemory.h"
22#include "../../include/freetype/internal/ftobjs.h"
23#include "../../include/freetype/ftlist.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  #ifdef _XYQ_MEM_DEBUG	/** XYQ 2006-10-12 */
167  FT_BASE_DEF( FT_Pointer )
168  ft_mem_allocdebug( FT_Memory  memory,
169                FT_Long    size, const char* file, int line,
170                FT_Error  *p_error )
171  {
172    FT_Error    error;
173    FT_Pointer  block = ft_mem_qallocdebug( memory, size, file, line, &error );
174
175    if ( !error && size > 0 )
176      FT_MEM_ZERO( block, size );
177
178    *p_error = error;
179    return block;
180  }
181
182
183  FT_BASE_DEF( FT_Pointer )
184  ft_mem_qallocdebug( FT_Memory  memory,
185                 FT_Long    size, const char* file, int line,
186                 FT_Error  *p_error )
187  {
188    FT_Error    error = FT_Err_Ok;
189    FT_Pointer  block = NULL;
190
191
192    if ( size > 0 )
193    {
194      block = memory->allocdebug( memory, size, file, line );
195      if ( block == NULL )
196        error = FT_Err_Out_Of_Memory;
197    }
198    else if ( size < 0 )
199    {
200      /* may help catch/prevent security issues */
201      error = FT_Err_Invalid_Argument;
202    }
203
204    *p_error = error;
205    return block;
206  }
207
208
209  FT_BASE_DEF( FT_Pointer )
210  ft_mem_reallocdebug( FT_Memory  memory,
211                  FT_Long    item_size,
212                  FT_Long    cur_count,
213                  FT_Long    new_count,
214                  void*      block, const char* file, int line,
215                  FT_Error  *p_error )
216  {
217    FT_Error  error = FT_Err_Ok;
218
219    block = ft_mem_qreallocdebug( memory, item_size,
220                             cur_count, new_count, block, file, line, &error );
221    if ( !error && new_count > cur_count )
222      FT_MEM_ZERO( (char*)block + cur_count * item_size,
223                   ( new_count - cur_count ) * item_size );
224
225    *p_error = error;
226    return block;
227  }
228
229
230  FT_BASE_DEF( FT_Pointer )
231  ft_mem_qreallocdebug( FT_Memory  memory,
232                   FT_Long    item_size,
233                   FT_Long    cur_count,
234                   FT_Long    new_count,
235                   void*      block, const char* file, int line,
236                   FT_Error  *p_error )
237  {
238    FT_Error  error = FT_Err_Ok;
239
240
241    if ( cur_count < 0 || new_count < 0 || item_size <= 0 )
242    {
243      /* may help catch/prevent nasty security issues */
244      error = FT_Err_Invalid_Argument;
245    }
246    else if ( new_count == 0 )
247    {
248      ft_mem_free( memory, block );
249      block = NULL;
250    }
251    else if ( new_count > FT_INT_MAX/item_size )
252    {
253      error = FT_Err_Array_Too_Large;
254    }
255    else if ( cur_count == 0 )
256    {
257      FT_ASSERT( block == NULL );
258
259      block = ft_mem_allocdebug( memory, new_count*item_size, file, line, &error );
260    }
261    else
262    {
263      FT_Pointer  block2;
264      FT_Long     cur_size = cur_count*item_size;
265      FT_Long     new_size = new_count*item_size;
266
267
268      block2 = memory->realloc( memory, cur_size, new_size, block );
269      if ( block2 == NULL )
270        error = FT_Err_Out_Of_Memory;
271      else
272        block = block2;
273    }
274
275    *p_error = error;
276    return block;
277  }
278#endif
279  FT_BASE_DEF( void )
280  ft_mem_free( FT_Memory   memory,
281               const void *P )
282  {
283    if ( P )
284      memory->free( memory, (void*)P );
285  }
286
287
288  FT_BASE_DEF( FT_Pointer )
289  ft_mem_dup( FT_Memory    memory,
290              const void*  address,
291              FT_ULong     size,
292              FT_Error    *p_error )
293  {
294    FT_Error    error;
295    FT_Pointer  p = ft_mem_qalloc( memory, size, &error );
296
297
298    if ( !error && address )
299      ft_memcpy( p, address, size );
300
301    *p_error = error;
302    return p;
303  }
304
305
306  FT_BASE_DEF( FT_Pointer )
307  ft_mem_strdup( FT_Memory    memory,
308                 const char*  str,
309                 FT_Error    *p_error )
310  {
311    FT_ULong  len = str ? (FT_ULong)ft_strlen( str ) + 1
312                        : 0;
313
314
315    return ft_mem_dup( memory, str, len, p_error );
316  }
317
318
319  FT_BASE_DEF( FT_Int )
320  ft_mem_strcpyn( char*        dst,
321                  const char*  src,
322                  FT_ULong     size )
323  {
324    while ( size > 1 && *src != 0 )
325    {
326      *dst++ = *src++;
327      size--;
328    }
329
330    *dst = 0;  /* always zero-terminate */
331
332    return *src != 0;
333  }
334
335
336  /*************************************************************************/
337  /*************************************************************************/
338  /*************************************************************************/
339  /*****                                                               *****/
340  /*****                                                               *****/
341  /*****            D O U B L Y   L I N K E D   L I S T S              *****/
342  /*****                                                               *****/
343  /*****                                                               *****/
344  /*************************************************************************/
345  /*************************************************************************/
346  /*************************************************************************/
347
348#undef  FT_COMPONENT
349#define FT_COMPONENT  trace_list
350
351  /* documentation is in ftlist.h */
352
353  FT_EXPORT_DEF( FT_ListNode )
354  FT_List_Find( FT_List  list,
355                void*    data )
356  {
357    FT_ListNode  cur;
358
359
360    cur = list->head;
361    while ( cur )
362    {
363      if ( cur->data == data )
364        return cur;
365
366      cur = cur->next;
367    }
368
369    return (FT_ListNode)0;
370  }
371
372
373  /* documentation is in ftlist.h */
374
375  FT_EXPORT_DEF( void )
376  FT_List_Add( FT_List      list,
377               FT_ListNode  node )
378  {
379    FT_ListNode  before = list->tail;
380
381
382    node->next = 0;
383    node->prev = before;
384
385    if ( before )
386      before->next = node;
387    else
388      list->head = node;
389
390    list->tail = node;
391  }
392
393
394  /* documentation is in ftlist.h */
395
396  FT_EXPORT_DEF( void )
397  FT_List_Insert( FT_List      list,
398                  FT_ListNode  node )
399  {
400    FT_ListNode  after = list->head;
401
402
403    node->next = after;
404    node->prev = 0;
405
406    if ( !after )
407      list->tail = node;
408    else
409      after->prev = node;
410
411    list->head = node;
412  }
413
414
415  /* documentation is in ftlist.h */
416
417  FT_EXPORT_DEF( void )
418  FT_List_Remove( FT_List      list,
419                  FT_ListNode  node )
420  {
421    FT_ListNode  before, after;
422
423
424    before = node->prev;
425    after  = node->next;
426
427    if ( before )
428      before->next = after;
429    else
430      list->head = after;
431
432    if ( after )
433      after->prev = before;
434    else
435      list->tail = before;
436  }
437
438
439  /* documentation is in ftlist.h */
440
441  FT_EXPORT_DEF( void )
442  FT_List_Up( FT_List      list,
443              FT_ListNode  node )
444  {
445    FT_ListNode  before, after;
446
447
448    before = node->prev;
449    after  = node->next;
450
451    /* check whether we are already on top of the list */
452    if ( !before )
453      return;
454
455    before->next = after;
456
457    if ( after )
458      after->prev = before;
459    else
460      list->tail = before;
461
462    node->prev       = 0;
463    node->next       = list->head;
464    list->head->prev = node;
465    list->head       = node;
466  }
467
468
469  /* documentation is in ftlist.h */
470
471  FT_EXPORT_DEF( FT_Error )
472  FT_List_Iterate( FT_List            list,
473                   FT_List_Iterator   iterator,
474                   void*              user )
475  {
476    FT_ListNode  cur   = list->head;
477    FT_Error     error = FT_Err_Ok;
478
479
480    while ( cur )
481    {
482      FT_ListNode  next = cur->next;
483
484
485      error = iterator( cur, user );
486      if ( error )
487        break;
488
489      cur = next;
490    }
491
492    return error;
493  }
494
495
496  /* documentation is in ftlist.h */
497
498  FT_EXPORT_DEF( void )
499  FT_List_Finalize( FT_List             list,
500                    FT_List_Destructor  destroy,
501                    FT_Memory           memory,
502                    void*               user )
503  {
504    FT_ListNode  cur;
505
506
507    cur = list->head;
508    while ( cur )
509    {
510      FT_ListNode  next = cur->next;
511      void*        data = cur->data;
512
513
514      if ( destroy )
515        destroy( memory, data, user );
516
517      FT_FREE( cur );
518      cur = next;
519    }
520
521    list->head = 0;
522    list->tail = 0;
523  }
524
525
526  FT_BASE_DEF( FT_UInt32 )
527  ft_highpow2( FT_UInt32  value )
528  {
529    FT_UInt32  value2;
530
531
532    /*
533     *  We simply clear the lowest bit in each iteration.  When
534     *  we reach 0, we know that the previous value was our result.
535     */
536    for ( ;; )
537    {
538      value2 = value & (value - 1);  /* clear lowest bit */
539      if ( value2 == 0 )
540        break;
541
542      value = value2;
543    }
544    return value;
545  }
546
547
548/* END */
549