ftsystem.c (13398B)
1 /**************************************************************************** 2 * 3 * ftsystem.c 4 * 5 * Windows-specific FreeType low-level system interface (body). 6 * 7 * Copyright (C) 2021-2025 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 /* we use our special ftconfig.h file, not the standard one */ 21 #include FT_CONFIG_CONFIG_H 22 #include <freetype/internal/ftdebug.h> 23 #include <freetype/ftsystem.h> 24 #include <freetype/fterrors.h> 25 #include <freetype/fttypes.h> 26 #include <freetype/internal/ftstream.h> 27 28 /* memory mapping and allocation includes and definitions */ 29 #define WIN32_LEAN_AND_MEAN 30 #include <windows.h> 31 32 33 /************************************************************************** 34 * 35 * MEMORY MANAGEMENT INTERFACE 36 * 37 */ 38 39 40 /************************************************************************** 41 * 42 * It is not necessary to do any error checking for the 43 * allocation-related functions. This will be done by the higher level 44 * routines like ft_mem_alloc() or ft_mem_realloc(). 45 * 46 */ 47 48 49 /************************************************************************** 50 * 51 * @Function: 52 * ft_alloc 53 * 54 * @Description: 55 * The memory allocation function. 56 * 57 * @Input: 58 * memory :: 59 * A pointer to the memory object. 60 * 61 * size :: 62 * The requested size in bytes. 63 * 64 * @Return: 65 * The address of newly allocated block. 66 */ 67 FT_CALLBACK_DEF( void* ) 68 ft_alloc( FT_Memory memory, 69 long size ) 70 { 71 return HeapAlloc( memory->user, 0, size ); 72 } 73 74 75 /************************************************************************** 76 * 77 * @Function: 78 * ft_realloc 79 * 80 * @Description: 81 * The memory reallocation function. 82 * 83 * @Input: 84 * memory :: 85 * A pointer to the memory object. 86 * 87 * cur_size :: 88 * The current size of the allocated memory block. 89 * 90 * new_size :: 91 * The newly requested size in bytes. 92 * 93 * block :: 94 * The current address of the block in memory. 95 * 96 * @Return: 97 * The address of the reallocated memory block. 98 */ 99 FT_CALLBACK_DEF( void* ) 100 ft_realloc( FT_Memory memory, 101 long cur_size, 102 long new_size, 103 void* block ) 104 { 105 FT_UNUSED( cur_size ); 106 107 return HeapReAlloc( memory->user, 0, block, new_size ); 108 } 109 110 111 /************************************************************************** 112 * 113 * @Function: 114 * ft_free 115 * 116 * @Description: 117 * The memory release function. 118 * 119 * @Input: 120 * memory :: 121 * A pointer to the memory object. 122 * 123 * block :: 124 * The address of block in memory to be freed. 125 */ 126 FT_CALLBACK_DEF( void ) 127 ft_free( FT_Memory memory, 128 void* block ) 129 { 130 HeapFree( memory->user, 0, block ); 131 } 132 133 134 /************************************************************************** 135 * 136 * RESOURCE MANAGEMENT INTERFACE 137 * 138 */ 139 140 141 /************************************************************************** 142 * 143 * The macro FT_COMPONENT is used in trace mode. It is an implicit 144 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 145 * messages during execution. 146 */ 147 #undef FT_COMPONENT 148 #define FT_COMPONENT io 149 150 /* We use the macro STREAM_FILE for convenience to extract the */ 151 /* system-specific stream handle from a given FreeType stream object */ 152 #define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer ) 153 154 155 /************************************************************************** 156 * 157 * @Function: 158 * ft_close_stream_by_munmap 159 * 160 * @Description: 161 * The function to close a stream which is opened by mmap. 162 * 163 * @Input: 164 * stream :: A pointer to the stream object. 165 */ 166 FT_CALLBACK_DEF( void ) 167 ft_close_stream_by_munmap( FT_Stream stream ) 168 { 169 UnmapViewOfFile( (LPCVOID)stream->descriptor.pointer ); 170 171 stream->descriptor.pointer = NULL; 172 stream->size = 0; 173 stream->base = NULL; 174 } 175 176 177 /************************************************************************** 178 * 179 * @Function: 180 * ft_close_stream_by_free 181 * 182 * @Description: 183 * The function to close a stream which is created by ft_alloc. 184 * 185 * @Input: 186 * stream :: A pointer to the stream object. 187 */ 188 FT_CALLBACK_DEF( void ) 189 ft_close_stream_by_free( FT_Stream stream ) 190 { 191 ft_free( stream->memory, stream->descriptor.pointer ); 192 193 stream->descriptor.pointer = NULL; 194 stream->size = 0; 195 stream->base = NULL; 196 } 197 198 199 /* support for Universal Windows Platform UWP, formerly WinRT */ 200 #ifdef _WINRT_DLL 201 202 #define PACK_DWORD64( hi, lo ) ( ( (DWORD64)(hi) << 32 ) | (DWORD)(lo) ) 203 204 #define CreateFileMapping( a, b, c, d, e, f ) \ 205 CreateFileMappingFromApp( a, b, c, PACK_DWORD64( d, e ), f ) 206 #define MapViewOfFile( a, b, c, d, e ) \ 207 MapViewOfFileFromApp( a, b, PACK_DWORD64( c, d ), e ) 208 209 FT_LOCAL_DEF( HANDLE ) 210 CreateFileA( LPCSTR lpFileName, 211 DWORD dwDesiredAccess, 212 DWORD dwShareMode, 213 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 214 DWORD dwCreationDisposition, 215 DWORD dwFlagsAndAttributes, 216 HANDLE hTemplateFile ) 217 { 218 int len; 219 LPWSTR lpFileNameW; 220 221 CREATEFILE2_EXTENDED_PARAMETERS createExParams = { 222 sizeof ( CREATEFILE2_EXTENDED_PARAMETERS ), 223 dwFlagsAndAttributes & 0x0000FFFF, 224 dwFlagsAndAttributes & 0xFFF00000, 225 dwFlagsAndAttributes & 0x000F0000, 226 lpSecurityAttributes, 227 hTemplateFile }; 228 229 230 /* allocate memory space for converted path name */ 231 len = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, 232 lpFileName, -1, NULL, 0 ); 233 234 lpFileNameW = (LPWSTR)_alloca( len * sizeof ( WCHAR ) ); 235 236 if ( !len || !lpFileNameW ) 237 { 238 FT_ERROR(( "FT_Stream_Open: cannot convert file name to LPWSTR\n" )); 239 return INVALID_HANDLE_VALUE; 240 } 241 242 /* now it is safe to do the translation */ 243 MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, 244 lpFileName, -1, lpFileNameW, len ); 245 246 /* open the file */ 247 return CreateFile2( lpFileNameW, dwDesiredAccess, dwShareMode, 248 dwCreationDisposition, &createExParams ); 249 } 250 251 #endif /* _WINRT_DLL */ 252 253 254 /* support for Windows CE */ 255 #ifdef _WIN32_WCE 256 257 /* malloc.h provides implementation of alloca()/_alloca() */ 258 #include <malloc.h> 259 260 FT_LOCAL_DEF( HANDLE ) 261 CreateFileA( LPCSTR lpFileName, 262 DWORD dwDesiredAccess, 263 DWORD dwShareMode, 264 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 265 DWORD dwCreationDisposition, 266 DWORD dwFlagsAndAttributes, 267 HANDLE hTemplateFile ) 268 { 269 int len; 270 LPWSTR lpFileNameW; 271 272 273 /* allocate memory space for converted path name */ 274 len = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, 275 lpFileName, -1, NULL, 0 ); 276 277 lpFileNameW = (LPWSTR)_alloca( len * sizeof ( WCHAR ) ); 278 279 if ( !len || !lpFileNameW ) 280 { 281 FT_ERROR(( "FT_Stream_Open: cannot convert file name to LPWSTR\n" )); 282 return INVALID_HANDLE_VALUE; 283 } 284 285 /* now it is safe to do the translation */ 286 MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, 287 lpFileName, -1, lpFileNameW, len ); 288 289 /* open the file */ 290 return CreateFileW( lpFileNameW, dwDesiredAccess, dwShareMode, 291 lpSecurityAttributes, dwCreationDisposition, 292 dwFlagsAndAttributes, hTemplateFile ); 293 } 294 295 #endif /* _WIN32_WCE */ 296 297 /* support for really old Windows */ 298 #if defined( _WIN32_WCE ) || defined ( _WIN32_WINDOWS ) || \ 299 ( defined( _WIN32_WINNT ) && _WIN32_WINNT <= 0x0400 ) 300 301 FT_LOCAL_DEF( BOOL ) 302 GetFileSizeEx( HANDLE hFile, 303 PLARGE_INTEGER lpFileSize ) 304 { 305 lpFileSize->u.LowPart = GetFileSize( hFile, 306 (DWORD *)&lpFileSize->u.HighPart ); 307 308 if ( lpFileSize->u.LowPart == INVALID_FILE_SIZE && 309 GetLastError() != NO_ERROR ) 310 return FALSE; 311 else 312 return TRUE; 313 } 314 315 #endif /* _WIN32_WCE || _WIN32_WINDOWS || _WIN32_WINNT <= 0x0400 */ 316 317 318 /* documentation is in ftobjs.h */ 319 320 FT_BASE_DEF( FT_Error ) 321 FT_Stream_Open( FT_Stream stream, 322 const char* filepathname ) 323 { 324 HANDLE file; 325 HANDLE fm; 326 LARGE_INTEGER size; 327 328 329 if ( !stream ) 330 return FT_THROW( Invalid_Stream_Handle ); 331 332 /* open the file */ 333 file = CreateFileA( (LPCSTR)filepathname, GENERIC_READ, FILE_SHARE_READ, 334 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); 335 if ( file == INVALID_HANDLE_VALUE ) 336 { 337 FT_ERROR(( "FT_Stream_Open:" )); 338 FT_ERROR(( " could not open `%s'\n", filepathname )); 339 return FT_THROW( Cannot_Open_Resource ); 340 } 341 342 if ( GetFileSizeEx( file, &size ) == FALSE ) 343 { 344 FT_ERROR(( "FT_Stream_Open:" )); 345 FT_ERROR(( " could not retrieve size of file `%s'\n", filepathname )); 346 goto Fail_Open; 347 } 348 349 /* `stream->size' is typedef'd to unsigned long (in `ftsystem.h'); */ 350 /* So avoid overflow caused by fonts in huge files larger than */ 351 /* 2GB, do a test. */ 352 if ( size.QuadPart > LONG_MAX ) 353 { 354 FT_ERROR(( "FT_Stream_Open: file is too big\n" )); 355 goto Fail_Open; 356 } 357 else if ( size.QuadPart == 0 ) 358 { 359 FT_ERROR(( "FT_Stream_Open: zero-length file\n" )); 360 goto Fail_Open; 361 } 362 363 fm = CreateFileMapping( file, NULL, PAGE_READONLY, 0, 0, NULL ); 364 if ( fm == NULL ) 365 { 366 FT_ERROR(( "FT_Stream_Open: can not map file\n" )); 367 goto Fail_Open; 368 } 369 370 /* Store only the low part of this 64 bits integer because long is */ 371 /* a 32 bits type. Anyway, a check has been done above to forbid */ 372 /* a size greater than LONG_MAX */ 373 stream->size = size.LowPart; 374 stream->pos = 0; 375 stream->base = (unsigned char *) 376 MapViewOfFile( fm, FILE_MAP_READ, 0, 0, 0 ); 377 378 CloseHandle( fm ); 379 380 if ( stream->base != NULL ) 381 stream->close = ft_close_stream_by_munmap; 382 else 383 { 384 DWORD total_read_count; 385 386 387 FT_ERROR(( "FT_Stream_Open:" )); 388 FT_ERROR(( " could not `mmap' file `%s'\n", filepathname )); 389 390 stream->base = (unsigned char*)ft_alloc( stream->memory, stream->size ); 391 392 if ( !stream->base ) 393 { 394 FT_ERROR(( "FT_Stream_Open:" )); 395 FT_ERROR(( " could not `alloc' memory\n" )); 396 goto Fail_Open; 397 } 398 399 total_read_count = 0; 400 do 401 { 402 DWORD read_count; 403 404 405 if ( ReadFile( file, 406 stream->base + total_read_count, 407 stream->size - total_read_count, 408 &read_count, NULL ) == FALSE ) 409 { 410 FT_ERROR(( "FT_Stream_Open:" )); 411 FT_ERROR(( " error while `read'ing file `%s'\n", filepathname )); 412 goto Fail_Read; 413 } 414 415 total_read_count += read_count; 416 417 } while ( total_read_count != stream->size ); 418 419 stream->close = ft_close_stream_by_free; 420 } 421 422 CloseHandle( file ); 423 424 stream->descriptor.pointer = stream->base; 425 stream->pathname.pointer = (char*)filepathname; 426 427 stream->read = NULL; 428 429 FT_TRACE1(( "FT_Stream_Open:" )); 430 FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", 431 filepathname, stream->size )); 432 433 return FT_Err_Ok; 434 435 Fail_Read: 436 ft_free( stream->memory, stream->base ); 437 438 Fail_Open: 439 CloseHandle( file ); 440 441 stream->base = NULL; 442 stream->size = 0; 443 stream->pos = 0; 444 445 return FT_THROW( Cannot_Open_Stream ); 446 } 447 448 449 #ifdef FT_DEBUG_MEMORY 450 451 extern FT_Int 452 ft_mem_debug_init( FT_Memory memory ); 453 454 extern void 455 ft_mem_debug_done( FT_Memory memory ); 456 457 #endif 458 459 460 /* documentation is in ftobjs.h */ 461 462 FT_BASE_DEF( FT_Memory ) 463 FT_New_Memory( void ) 464 { 465 HANDLE heap; 466 FT_Memory memory; 467 468 469 heap = GetProcessHeap(); 470 memory = heap ? (FT_Memory)HeapAlloc( heap, 0, sizeof ( *memory ) ) 471 : NULL; 472 473 if ( memory ) 474 { 475 memory->user = heap; 476 memory->alloc = ft_alloc; 477 memory->realloc = ft_realloc; 478 memory->free = ft_free; 479 #ifdef FT_DEBUG_MEMORY 480 ft_mem_debug_init( memory ); 481 #endif 482 } 483 484 return memory; 485 } 486 487 488 /* documentation is in ftobjs.h */ 489 490 FT_BASE_DEF( void ) 491 FT_Done_Memory( FT_Memory memory ) 492 { 493 #ifdef FT_DEBUG_MEMORY 494 ft_mem_debug_done( memory ); 495 #endif 496 memory->free( memory, memory ); 497 } 498 499 500 /* END */