1 /**************************************************************************** 2 * 3 * ftutil.c 4 * 5 * FreeType utility file for memory and list management (body). 6 * 7 * Copyright 2002-2018 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 ) 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 trace_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