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