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