1 /**************************************************************************** 2 * 3 * ftsystem.c 4 * 5 * Windows-specific FreeType low-level system interface (body). 6 * 7 * Copyright (C) 2021-2022 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* ) ft_alloc(FT_Memory memory,long size)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* ) ft_realloc(FT_Memory memory,long cur_size,long new_size,void * block)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 ) ft_free(FT_Memory memory,void * block)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 ) ft_close_stream_by_munmap(FT_Stream stream)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 ) ft_close_stream_by_free(FT_Stream stream)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 /* non-desktop Universal Windows Platform */ 200 #if defined( WINAPI_FAMILY ) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP 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 ) CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)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 252 253 254 #if defined( _WIN32_WCE ) 255 256 /* malloc.h provides implementation of alloca()/_alloca() */ 257 #include <malloc.h> 258 259 FT_LOCAL_DEF( HANDLE ) CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)260 CreateFileA( LPCSTR lpFileName, 261 DWORD dwDesiredAccess, 262 DWORD dwShareMode, 263 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 264 DWORD dwCreationDisposition, 265 DWORD dwFlagsAndAttributes, 266 HANDLE hTemplateFile ) 267 { 268 int len; 269 LPWSTR lpFileNameW; 270 271 272 /* allocate memory space for converted path name */ 273 len = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, 274 lpFileName, -1, NULL, 0 ); 275 276 lpFileNameW = (LPWSTR)_alloca( len * sizeof ( WCHAR ) ); 277 278 if ( !len || !lpFileNameW ) 279 { 280 FT_ERROR(( "FT_Stream_Open: cannot convert file name to LPWSTR\n" )); 281 return INVALID_HANDLE_VALUE; 282 } 283 284 /* now it is safe to do the translation */ 285 MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, 286 lpFileName, -1, lpFileNameW, len ); 287 288 /* open the file */ 289 return CreateFileW( lpFileNameW, dwDesiredAccess, dwShareMode, 290 lpSecurityAttributes, dwCreationDisposition, 291 dwFlagsAndAttributes, hTemplateFile ); 292 } 293 294 #endif 295 296 297 #if defined( _WIN32_WCE ) || defined ( _WIN32_WINDOWS ) || \ 298 !defined( _WIN32_WINNT ) || _WIN32_WINNT <= 0x0400 299 300 FT_LOCAL_DEF( BOOL ) GetFileSizeEx(HANDLE hFile,PLARGE_INTEGER lpFileSize)301 GetFileSizeEx( HANDLE hFile, 302 PLARGE_INTEGER lpFileSize ) 303 { 304 lpFileSize->u.LowPart = GetFileSize( hFile, 305 (DWORD *)&lpFileSize->u.HighPart ); 306 307 if ( lpFileSize->u.LowPart == INVALID_FILE_SIZE && 308 GetLastError() != NO_ERROR ) 309 return FALSE; 310 else 311 return TRUE; 312 } 313 314 #endif 315 316 317 /* documentation is in ftobjs.h */ 318 319 FT_BASE_DEF( FT_Error ) FT_Stream_Open(FT_Stream stream,const char * filepathname)320 FT_Stream_Open( FT_Stream stream, 321 const char* filepathname ) 322 { 323 HANDLE file; 324 HANDLE fm; 325 LARGE_INTEGER size; 326 327 328 if ( !stream ) 329 return FT_THROW( Invalid_Stream_Handle ); 330 331 /* open the file */ 332 file = CreateFileA( (LPCSTR)filepathname, GENERIC_READ, FILE_SHARE_READ, 333 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); 334 if ( file == INVALID_HANDLE_VALUE ) 335 { 336 FT_ERROR(( "FT_Stream_Open:" )); 337 FT_ERROR(( " could not open `%s'\n", filepathname )); 338 return FT_THROW( Cannot_Open_Resource ); 339 } 340 341 if ( GetFileSizeEx( file, &size ) == FALSE ) 342 { 343 FT_ERROR(( "FT_Stream_Open:" )); 344 FT_ERROR(( " could not retrieve size of file `%s'\n", filepathname )); 345 goto Fail_Open; 346 } 347 348 /* `stream->size' is typedef'd to unsigned long (in `ftsystem.h'); */ 349 /* So avoid overflow caused by fonts in huge files larger than */ 350 /* 2GB, do a test. */ 351 if ( size.QuadPart > LONG_MAX ) 352 { 353 FT_ERROR(( "FT_Stream_Open: file is too big\n" )); 354 goto Fail_Open; 355 } 356 else if ( size.QuadPart == 0 ) 357 { 358 FT_ERROR(( "FT_Stream_Open: zero-length file\n" )); 359 goto Fail_Open; 360 } 361 362 fm = CreateFileMapping( file, NULL, PAGE_READONLY, 0, 0, NULL ); 363 if ( fm == NULL ) 364 { 365 FT_ERROR(( "FT_Stream_Open: can not map file\n" )); 366 goto Fail_Open; 367 } 368 369 /* Store only the low part of this 64 bits integer because long is */ 370 /* a 32 bits type. Anyway, a check has been done above to forbid */ 371 /* a size greater than LONG_MAX */ 372 stream->size = size.LowPart; 373 stream->pos = 0; 374 stream->base = (unsigned char *) 375 MapViewOfFile( fm, FILE_MAP_READ, 0, 0, 0 ); 376 377 CloseHandle( fm ); 378 379 if ( stream->base != NULL ) 380 stream->close = ft_close_stream_by_munmap; 381 else 382 { 383 DWORD total_read_count; 384 385 386 FT_ERROR(( "FT_Stream_Open:" )); 387 FT_ERROR(( " could not `mmap' file `%s'\n", filepathname )); 388 389 stream->base = (unsigned char*)ft_alloc( stream->memory, stream->size ); 390 391 if ( !stream->base ) 392 { 393 FT_ERROR(( "FT_Stream_Open:" )); 394 FT_ERROR(( " could not `alloc' memory\n" )); 395 goto Fail_Open; 396 } 397 398 total_read_count = 0; 399 do 400 { 401 DWORD read_count; 402 403 404 if ( ReadFile( file, 405 stream->base + total_read_count, 406 stream->size - total_read_count, 407 &read_count, NULL ) == FALSE ) 408 { 409 FT_ERROR(( "FT_Stream_Open:" )); 410 FT_ERROR(( " error while `read'ing file `%s'\n", filepathname )); 411 goto Fail_Read; 412 } 413 414 total_read_count += read_count; 415 416 } while ( total_read_count != stream->size ); 417 418 stream->close = ft_close_stream_by_free; 419 } 420 421 CloseHandle( file ); 422 423 stream->descriptor.pointer = stream->base; 424 stream->pathname.pointer = (char*)filepathname; 425 426 stream->read = NULL; 427 428 FT_TRACE1(( "FT_Stream_Open:" )); 429 FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", 430 filepathname, stream->size )); 431 432 return FT_Err_Ok; 433 434 Fail_Read: 435 ft_free( stream->memory, stream->base ); 436 437 Fail_Open: 438 CloseHandle( file ); 439 440 stream->base = NULL; 441 stream->size = 0; 442 stream->pos = 0; 443 444 return FT_THROW( Cannot_Open_Stream ); 445 } 446 447 448 #ifdef FT_DEBUG_MEMORY 449 450 extern FT_Int 451 ft_mem_debug_init( FT_Memory memory ); 452 453 extern void 454 ft_mem_debug_done( FT_Memory memory ); 455 456 #endif 457 458 459 /* documentation is in ftobjs.h */ 460 461 FT_BASE_DEF( FT_Memory ) FT_New_Memory(void)462 FT_New_Memory( void ) 463 { 464 HANDLE heap; 465 FT_Memory memory; 466 467 468 heap = GetProcessHeap(); 469 memory = heap ? (FT_Memory)HeapAlloc( heap, 0, sizeof ( *memory ) ) 470 : NULL; 471 472 if ( memory ) 473 { 474 memory->user = heap; 475 memory->alloc = ft_alloc; 476 memory->realloc = ft_realloc; 477 memory->free = ft_free; 478 #ifdef FT_DEBUG_MEMORY 479 ft_mem_debug_init( memory ); 480 #endif 481 } 482 483 return memory; 484 } 485 486 487 /* documentation is in ftobjs.h */ 488 489 FT_BASE_DEF( void ) FT_Done_Memory(FT_Memory memory)490 FT_Done_Memory( FT_Memory memory ) 491 { 492 #ifdef FT_DEBUG_MEMORY 493 ft_mem_debug_done( memory ); 494 #endif 495 memory->free( memory, memory ); 496 } 497 498 499 /* END */ 500