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