1 /**************************************************************************** 2 * 3 * ftsystem.c 4 * 5 * Windows-specific FreeType low-level system interface (body). 6 * 7 * Copyright (C) 2021 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 #ifdef _WIN32_WCE 200 201 FT_LOCAL_DEF( HANDLE ) CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)202 CreateFileA( LPCSTR lpFileName, 203 DWORD dwDesiredAccess, 204 DWORD dwShareMode, 205 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 206 DWORD dwCreationDisposition, 207 DWORD dwFlagsAndAttributes, 208 HANDLE hTemplateFile ) 209 { 210 int len; 211 LPWSTR lpFileNameW; 212 213 214 /* allocate memory space for converted path name */ 215 len = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, 216 lpFileName, -1, NULL, 0 ); 217 218 lpFileNameW = (LPWSTR)_alloca( len * sizeof ( WCHAR ) ); 219 220 if ( !len || !lpFileNameW ) 221 { 222 FT_ERROR(( "FT_Stream_Open: cannot convert file name to LPWSTR\n" )); 223 return INVALID_HANDLE_VALUE; 224 } 225 226 /* now it is safe to do the translation */ 227 MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, 228 lpFileName, -1, lpFileNameW, len ); 229 230 /* open the file */ 231 return CreateFileW( lpFileNameW, dwDesiredAccess, dwShareMode, 232 lpSecurityAttributes, dwCreationDisposition, 233 dwFlagsAndAttributes, hTemplateFile ); 234 } 235 236 237 FT_LOCAL_DEF( BOOL ) GetFileSizeEx(HANDLE hFile,PLARGE_INTEGER lpFileSize)238 GetFileSizeEx( HANDLE hFile, 239 PLARGE_INTEGER lpFileSize ) 240 { 241 lpFileSize->u.LowPart = GetFileSize( hFile, 242 (DWORD *)&lpFileSize->u.HighPart ); 243 244 if ( lpFileSize->u.LowPart == INVALID_FILE_SIZE && 245 GetLastError() != NO_ERROR ) 246 return FALSE; 247 else 248 return TRUE; 249 } 250 251 #endif /* _WIN32_WCE */ 252 253 254 /* documentation is in ftobjs.h */ 255 256 FT_BASE_DEF( FT_Error ) FT_Stream_Open(FT_Stream stream,const char * filepathname)257 FT_Stream_Open( FT_Stream stream, 258 const char* filepathname ) 259 { 260 HANDLE file; 261 HANDLE fm; 262 LARGE_INTEGER size; 263 264 265 if ( !stream ) 266 return FT_THROW( Invalid_Stream_Handle ); 267 268 /* open the file */ 269 file = CreateFileA( (LPCSTR)filepathname, GENERIC_READ, FILE_SHARE_READ, 270 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); 271 if ( file == INVALID_HANDLE_VALUE ) 272 { 273 FT_ERROR(( "FT_Stream_Open:" )); 274 FT_ERROR(( " could not open `%s'\n", filepathname )); 275 return FT_THROW( Cannot_Open_Resource ); 276 } 277 278 if ( GetFileSizeEx( file, &size ) == FALSE ) 279 { 280 FT_ERROR(( "FT_Stream_Open:" )); 281 FT_ERROR(( " could not retrieve size of file `%s'\n", filepathname )); 282 goto Fail_Open; 283 } 284 285 /* `stream->size' is typedef'd to unsigned long (in `ftsystem.h'); */ 286 /* So avoid overflow caused by fonts in huge files larger than */ 287 /* 2GB, do a test. */ 288 if ( size.QuadPart > LONG_MAX ) 289 { 290 FT_ERROR(( "FT_Stream_Open: file is too big\n" )); 291 goto Fail_Open; 292 } 293 else if ( size.QuadPart == 0 ) 294 { 295 FT_ERROR(( "FT_Stream_Open: zero-length file\n" )); 296 goto Fail_Open; 297 } 298 299 fm = CreateFileMapping( file, NULL, PAGE_READONLY, 0, 0, NULL ); 300 if ( fm == NULL ) 301 { 302 FT_ERROR(( "FT_Stream_Open: can not map file\n" )); 303 goto Fail_Open; 304 } 305 306 /* Store only the low part of this 64 bits integer because long is */ 307 /* a 32 bits type. Anyway, a check has been done above to forbid */ 308 /* a size greater than LONG_MAX */ 309 stream->size = size.LowPart; 310 stream->pos = 0; 311 stream->base = (unsigned char *) 312 MapViewOfFile( fm, FILE_MAP_READ, 0, 0, 0 ); 313 314 CloseHandle( fm ); 315 316 if ( stream->base != NULL ) 317 stream->close = ft_close_stream_by_munmap; 318 else 319 { 320 DWORD total_read_count; 321 322 323 FT_ERROR(( "FT_Stream_Open:" )); 324 FT_ERROR(( " could not `mmap' file `%s'\n", filepathname )); 325 326 stream->base = (unsigned char*)ft_alloc( stream->memory, stream->size ); 327 328 if ( !stream->base ) 329 { 330 FT_ERROR(( "FT_Stream_Open:" )); 331 FT_ERROR(( " could not `alloc' memory\n" )); 332 goto Fail_Open; 333 } 334 335 total_read_count = 0; 336 do 337 { 338 DWORD read_count; 339 340 341 if ( ReadFile( file, 342 stream->base + total_read_count, 343 stream->size - total_read_count, 344 &read_count, NULL ) == FALSE ) 345 { 346 FT_ERROR(( "FT_Stream_Open:" )); 347 FT_ERROR(( " error while `read'ing file `%s'\n", filepathname )); 348 goto Fail_Read; 349 } 350 351 total_read_count += read_count; 352 353 } while ( total_read_count != stream->size ); 354 355 stream->close = ft_close_stream_by_free; 356 } 357 358 CloseHandle( file ); 359 360 stream->descriptor.pointer = stream->base; 361 stream->pathname.pointer = (char*)filepathname; 362 363 stream->read = NULL; 364 365 FT_TRACE1(( "FT_Stream_Open:" )); 366 FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", 367 filepathname, stream->size )); 368 369 return FT_Err_Ok; 370 371 Fail_Read: 372 ft_free( stream->memory, stream->base ); 373 374 Fail_Open: 375 CloseHandle( file ); 376 377 stream->base = NULL; 378 stream->size = 0; 379 stream->pos = 0; 380 381 return FT_THROW( Cannot_Open_Stream ); 382 } 383 384 385 #ifdef FT_DEBUG_MEMORY 386 387 extern FT_Int 388 ft_mem_debug_init( FT_Memory memory ); 389 390 extern void 391 ft_mem_debug_done( FT_Memory memory ); 392 393 #endif 394 395 396 /* documentation is in ftobjs.h */ 397 398 FT_BASE_DEF( FT_Memory ) FT_New_Memory(void)399 FT_New_Memory( void ) 400 { 401 HANDLE heap; 402 FT_Memory memory; 403 404 405 heap = GetProcessHeap(); 406 memory = heap ? (FT_Memory)HeapAlloc( heap, 0, sizeof ( *memory ) ) 407 : NULL; 408 409 if ( memory ) 410 { 411 memory->user = heap; 412 memory->alloc = ft_alloc; 413 memory->realloc = ft_realloc; 414 memory->free = ft_free; 415 #ifdef FT_DEBUG_MEMORY 416 ft_mem_debug_init( memory ); 417 #endif 418 } 419 420 return memory; 421 } 422 423 424 /* documentation is in ftobjs.h */ 425 426 FT_BASE_DEF( void ) FT_Done_Memory(FT_Memory memory)427 FT_Done_Memory( FT_Memory memory ) 428 { 429 #ifdef FT_DEBUG_MEMORY 430 ft_mem_debug_done( memory ); 431 #endif 432 memory->free( memory, memory ); 433 } 434 435 436 /* END */ 437