Imported Upstream version 2.13.2
[platform/upstream/freetype2.git] / builds / windows / ftsystem.c
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 */