1 /***************************************************************************/ 2 /* */ 3 /* ftutil.c */ 4 /* */ 5 /* FreeType utility file for memory and list management (body). */ 6 /* */ 7 /* Copyright 2002-2017 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 && 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 && 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 = 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 ) 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 ) ft_mem_free(FT_Memory memory,const void * P)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 ) ft_mem_dup(FT_Memory memory,const void * address,FT_ULong size,FT_Error * p_error)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, (FT_Long)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 ) ft_mem_strdup(FT_Memory memory,const char * str,FT_Error * p_error)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 ) ft_mem_strcpyn(char * dst,const char * src,FT_ULong size)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 ) FT_List_Find(FT_List list,void * data)242 FT_List_Find( FT_List list, 243 void* data ) 244 { 245 FT_ListNode cur; 246 247 248 if ( !list ) 249 return NULL; 250 251 cur = list->head; 252 while ( cur ) 253 { 254 if ( cur->data == data ) 255 return cur; 256 257 cur = cur->next; 258 } 259 260 return NULL; 261 } 262 263 264 /* documentation is in ftlist.h */ 265 266 FT_EXPORT_DEF( void ) FT_List_Add(FT_List list,FT_ListNode node)267 FT_List_Add( FT_List list, 268 FT_ListNode node ) 269 { 270 FT_ListNode before; 271 272 273 if ( !list || !node ) 274 return; 275 276 before = list->tail; 277 278 node->next = NULL; 279 node->prev = before; 280 281 if ( before ) 282 before->next = node; 283 else 284 list->head = node; 285 286 list->tail = node; 287 } 288 289 290 /* documentation is in ftlist.h */ 291 292 FT_EXPORT_DEF( void ) FT_List_Insert(FT_List list,FT_ListNode node)293 FT_List_Insert( FT_List list, 294 FT_ListNode node ) 295 { 296 FT_ListNode after; 297 298 299 if ( !list || !node ) 300 return; 301 302 after = list->head; 303 304 node->next = after; 305 node->prev = NULL; 306 307 if ( !after ) 308 list->tail = node; 309 else 310 after->prev = node; 311 312 list->head = node; 313 } 314 315 316 /* documentation is in ftlist.h */ 317 318 FT_EXPORT_DEF( void ) FT_List_Remove(FT_List list,FT_ListNode node)319 FT_List_Remove( FT_List list, 320 FT_ListNode node ) 321 { 322 FT_ListNode before, after; 323 324 325 if ( !list || !node ) 326 return; 327 328 before = node->prev; 329 after = node->next; 330 331 if ( before ) 332 before->next = after; 333 else 334 list->head = after; 335 336 if ( after ) 337 after->prev = before; 338 else 339 list->tail = before; 340 } 341 342 343 /* documentation is in ftlist.h */ 344 345 FT_EXPORT_DEF( void ) FT_List_Up(FT_List list,FT_ListNode node)346 FT_List_Up( FT_List list, 347 FT_ListNode node ) 348 { 349 FT_ListNode before, after; 350 351 352 if ( !list || !node ) 353 return; 354 355 before = node->prev; 356 after = node->next; 357 358 /* check whether we are already on top of the list */ 359 if ( !before ) 360 return; 361 362 before->next = after; 363 364 if ( after ) 365 after->prev = before; 366 else 367 list->tail = before; 368 369 node->prev = NULL; 370 node->next = list->head; 371 list->head->prev = node; 372 list->head = node; 373 } 374 375 376 /* documentation is in ftlist.h */ 377 378 FT_EXPORT_DEF( FT_Error ) FT_List_Iterate(FT_List list,FT_List_Iterator iterator,void * user)379 FT_List_Iterate( FT_List list, 380 FT_List_Iterator iterator, 381 void* user ) 382 { 383 FT_ListNode cur; 384 FT_Error error = FT_Err_Ok; 385 386 387 if ( !list || !iterator ) 388 return FT_THROW( Invalid_Argument ); 389 390 cur = list->head; 391 392 while ( cur ) 393 { 394 FT_ListNode next = cur->next; 395 396 397 error = iterator( cur, user ); 398 if ( error ) 399 break; 400 401 cur = next; 402 } 403 404 return error; 405 } 406 407 408 /* documentation is in ftlist.h */ 409 410 FT_EXPORT_DEF( void ) FT_List_Finalize(FT_List list,FT_List_Destructor destroy,FT_Memory memory,void * user)411 FT_List_Finalize( FT_List list, 412 FT_List_Destructor destroy, 413 FT_Memory memory, 414 void* user ) 415 { 416 FT_ListNode cur; 417 418 419 if ( !list || !memory ) 420 return; 421 422 cur = list->head; 423 while ( cur ) 424 { 425 FT_ListNode next = cur->next; 426 void* data = cur->data; 427 428 429 if ( destroy ) 430 destroy( memory, data, user ); 431 432 FT_FREE( cur ); 433 cur = next; 434 } 435 436 list->head = NULL; 437 list->tail = NULL; 438 } 439 440 441 /* END */ 442