1 /****************************************************************************
2 *
3 * ftsystem.c
4 *
5 * Windows-specific FreeType low-level system interface (body).
6 *
7 * Copyright (C) 2021-2023 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 /* 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 )
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 )
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 )
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 )
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 )
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 )
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 */