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 )
  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 )
  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 && 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 )
 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 && 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 )
 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  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 */