• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftsystem.c                                                             */
4 /*                                                                         */
5 /*    Unix-specific FreeType low-level system interface (body).            */
6 /*                                                                         */
7 /*  Copyright (C) 1996-2020 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 includes and definitions */
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 
33 #include <sys/mman.h>
34 #ifndef MAP_FILE
35 #define MAP_FILE  0x00
36 #endif
37 
38 #ifdef MUNMAP_USES_VOIDP
39 #define MUNMAP_ARG_CAST  void *
40 #else
41 #define MUNMAP_ARG_CAST  char *
42 #endif
43 
44 #ifdef NEED_MUNMAP_DECL
45 
46 #ifdef __cplusplus
47   extern "C"
48 #else
49   extern
50 #endif
51   int
52   munmap( char*  addr,
53           int    len );
54 
55 #define MUNMAP_ARG_CAST  char *
56 
57 #endif /* NEED_DECLARATION_MUNMAP */
58 
59 
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 
63 #ifdef HAVE_FCNTL_H
64 #include <fcntl.h>
65 #endif
66 
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <errno.h>
71 
72 
73   /*************************************************************************/
74   /*                                                                       */
75   /*                       MEMORY MANAGEMENT INTERFACE                     */
76   /*                                                                       */
77   /*************************************************************************/
78 
79 
80   /*************************************************************************/
81   /*                                                                       */
82   /* <Function>                                                            */
83   /*    ft_alloc                                                           */
84   /*                                                                       */
85   /* <Description>                                                         */
86   /*    The memory allocation function.                                    */
87   /*                                                                       */
88   /* <Input>                                                               */
89   /*    memory :: A pointer to the memory object.                          */
90   /*                                                                       */
91   /*    size   :: The requested size in bytes.                             */
92   /*                                                                       */
93   /* <Return>                                                              */
94   /*    The address of newly allocated block.                              */
95   /*                                                                       */
96   FT_CALLBACK_DEF( void* )
ft_alloc(FT_Memory memory,long size)97   ft_alloc( FT_Memory  memory,
98             long       size )
99   {
100     FT_UNUSED( memory );
101 
102     return malloc( size );
103   }
104 
105 
106   /*************************************************************************/
107   /*                                                                       */
108   /* <Function>                                                            */
109   /*    ft_realloc                                                         */
110   /*                                                                       */
111   /* <Description>                                                         */
112   /*    The memory reallocation function.                                  */
113   /*                                                                       */
114   /* <Input>                                                               */
115   /*    memory   :: A pointer to the memory object.                        */
116   /*                                                                       */
117   /*    cur_size :: The current size of the allocated memory block.        */
118   /*                                                                       */
119   /*    new_size :: The newly requested size in bytes.                     */
120   /*                                                                       */
121   /*    block    :: The current address of the block in memory.            */
122   /*                                                                       */
123   /* <Return>                                                              */
124   /*    The address of the reallocated memory block.                       */
125   /*                                                                       */
126   FT_CALLBACK_DEF( void* )
ft_realloc(FT_Memory memory,long cur_size,long new_size,void * block)127   ft_realloc( FT_Memory  memory,
128               long       cur_size,
129               long       new_size,
130               void*      block )
131   {
132     FT_UNUSED( memory );
133     FT_UNUSED( cur_size );
134 
135     return realloc( block, new_size );
136   }
137 
138 
139   /*************************************************************************/
140   /*                                                                       */
141   /* <Function>                                                            */
142   /*    ft_free                                                            */
143   /*                                                                       */
144   /* <Description>                                                         */
145   /*    The memory release function.                                       */
146   /*                                                                       */
147   /* <Input>                                                               */
148   /*    memory :: A pointer to the memory object.                          */
149   /*                                                                       */
150   /*    block  :: The address of block in memory to be freed.              */
151   /*                                                                       */
152   FT_CALLBACK_DEF( void )
ft_free(FT_Memory memory,void * block)153   ft_free( FT_Memory  memory,
154            void*      block )
155   {
156     FT_UNUSED( memory );
157 
158     free( block );
159   }
160 
161 
162   /*************************************************************************/
163   /*                                                                       */
164   /*                     RESOURCE MANAGEMENT INTERFACE                     */
165   /*                                                                       */
166   /*************************************************************************/
167 
168 
169   /*************************************************************************/
170   /*                                                                       */
171   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
172   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
173   /* messages during execution.                                            */
174   /*                                                                       */
175 #undef  FT_COMPONENT
176 #define FT_COMPONENT  io
177 
178   /* We use the macro STREAM_FILE for convenience to extract the       */
179   /* system-specific stream handle from a given FreeType stream object */
180 #define STREAM_FILE( stream )  ( (FILE*)stream->descriptor.pointer )
181 
182 
183   /*************************************************************************/
184   /*                                                                       */
185   /* <Function>                                                            */
186   /*    ft_close_stream_by_munmap                                          */
187   /*                                                                       */
188   /* <Description>                                                         */
189   /*    The function to close a stream which is opened by mmap.            */
190   /*                                                                       */
191   /* <Input>                                                               */
192   /*    stream :: A pointer to the stream object.                          */
193   /*                                                                       */
194   FT_CALLBACK_DEF( void )
ft_close_stream_by_munmap(FT_Stream stream)195   ft_close_stream_by_munmap( FT_Stream  stream )
196   {
197     munmap( (MUNMAP_ARG_CAST)stream->descriptor.pointer, stream->size );
198 
199     stream->descriptor.pointer = NULL;
200     stream->size               = 0;
201     stream->base               = 0;
202   }
203 
204 
205   /*************************************************************************/
206   /*                                                                       */
207   /* <Function>                                                            */
208   /*    ft_close_stream_by_free                                            */
209   /*                                                                       */
210   /* <Description>                                                         */
211   /*    The function to close a stream which is created by ft_alloc.       */
212   /*                                                                       */
213   /* <Input>                                                               */
214   /*    stream :: A pointer to the stream object.                          */
215   /*                                                                       */
216   FT_CALLBACK_DEF( void )
ft_close_stream_by_free(FT_Stream stream)217   ft_close_stream_by_free( FT_Stream  stream )
218   {
219     ft_free( NULL, stream->descriptor.pointer );
220 
221     stream->descriptor.pointer = NULL;
222     stream->size               = 0;
223     stream->base               = 0;
224   }
225 
226 
227   /* documentation is in ftobjs.h */
228 
229   FT_BASE_DEF( FT_Error )
FT_Stream_Open(FT_Stream stream,const char * filepathname)230   FT_Stream_Open( FT_Stream    stream,
231                   const char*  filepathname )
232   {
233     int          file;
234     struct stat  stat_buf;
235 
236 
237     if ( !stream )
238       return FT_THROW( Invalid_Stream_Handle );
239 
240     /* open the file */
241     file = open( filepathname, O_RDONLY );
242     if ( file < 0 )
243     {
244       FT_ERROR(( "FT_Stream_Open:" ));
245       FT_ERROR(( " could not open `%s'\n", filepathname ));
246       return FT_THROW( Cannot_Open_Resource );
247     }
248 
249     /* Here we ensure that a "fork" will _not_ duplicate   */
250     /* our opened input streams on Unix.  This is critical */
251     /* since it avoids some (possible) access control      */
252     /* issues and cleans up the kernel file table a bit.   */
253     /*                                                     */
254 #ifdef F_SETFD
255 #ifdef FD_CLOEXEC
256     (void)fcntl( file, F_SETFD, FD_CLOEXEC );
257 #else
258     (void)fcntl( file, F_SETFD, 1 );
259 #endif /* FD_CLOEXEC */
260 #endif /* F_SETFD */
261 
262     if ( fstat( file, &stat_buf ) < 0 )
263     {
264       FT_ERROR(( "FT_Stream_Open:" ));
265       FT_ERROR(( " could not `fstat' file `%s'\n", filepathname ));
266       goto Fail_Map;
267     }
268 
269     /* XXX: TODO -- real 64bit platform support                        */
270     /*                                                                 */
271     /* `stream->size' is typedef'd to unsigned long (in `ftsystem.h'); */
272     /* `stat_buf.st_size', however, is usually typedef'd to off_t      */
273     /* (in sys/stat.h).                                                */
274     /* On some platforms, the former is 32bit and the latter is 64bit. */
275     /* To avoid overflow caused by fonts in huge files larger than     */
276     /* 2GB, do a test.  Temporary fix proposed by Sean McBride.        */
277     /*                                                                 */
278     if ( stat_buf.st_size > LONG_MAX )
279     {
280       FT_ERROR(( "FT_Stream_Open: file is too big\n" ));
281       goto Fail_Map;
282     }
283     else if ( stat_buf.st_size == 0 )
284     {
285       FT_ERROR(( "FT_Stream_Open: zero-length file\n" ));
286       goto Fail_Map;
287     }
288 
289     /* This cast potentially truncates a 64bit to 32bit! */
290     stream->size = (unsigned long)stat_buf.st_size;
291     stream->pos  = 0;
292     stream->base = (unsigned char *)mmap( NULL,
293                                           stream->size,
294                                           PROT_READ,
295                                           MAP_FILE | MAP_PRIVATE,
296                                           file,
297                                           0 );
298 
299     /* on some RTOS, mmap might return 0 */
300     if ( (long)stream->base != -1 && stream->base != NULL )
301       stream->close = ft_close_stream_by_munmap;
302     else
303     {
304       ssize_t  total_read_count;
305 
306 
307       FT_ERROR(( "FT_Stream_Open:" ));
308       FT_ERROR(( " could not `mmap' file `%s'\n", filepathname ));
309 
310       stream->base = (unsigned char*)ft_alloc( NULL, stream->size );
311 
312       if ( !stream->base )
313       {
314         FT_ERROR(( "FT_Stream_Open:" ));
315         FT_ERROR(( " could not `alloc' memory\n" ));
316         goto Fail_Map;
317       }
318 
319       total_read_count = 0;
320       do
321       {
322         ssize_t  read_count;
323 
324 
325         read_count = read( file,
326                            stream->base + total_read_count,
327                            stream->size - total_read_count );
328 
329         if ( read_count <= 0 )
330         {
331           if ( read_count == -1 && errno == EINTR )
332             continue;
333 
334           FT_ERROR(( "FT_Stream_Open:" ));
335           FT_ERROR(( " error while `read'ing file `%s'\n", filepathname ));
336           goto Fail_Read;
337         }
338 
339         total_read_count += read_count;
340 
341       } while ( (unsigned long)total_read_count != stream->size );
342 
343       stream->close = ft_close_stream_by_free;
344     }
345 
346     close( file );
347 
348     stream->descriptor.pointer = stream->base;
349     stream->pathname.pointer   = (char*)filepathname;
350 
351     stream->read = 0;
352 
353     FT_TRACE1(( "FT_Stream_Open:" ));
354     FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n",
355                 filepathname, stream->size ));
356 
357     return FT_Err_Ok;
358 
359   Fail_Read:
360     ft_free( NULL, stream->base );
361 
362   Fail_Map:
363     close( file );
364 
365     stream->base = NULL;
366     stream->size = 0;
367     stream->pos  = 0;
368 
369     return FT_THROW( Cannot_Open_Stream );
370   }
371 
372 
373 #ifdef FT_DEBUG_MEMORY
374 
375   extern FT_Int
376   ft_mem_debug_init( FT_Memory  memory );
377 
378   extern void
379   ft_mem_debug_done( FT_Memory  memory );
380 
381 #endif
382 
383 
384   /* documentation is in ftobjs.h */
385 
386   FT_BASE_DEF( FT_Memory )
FT_New_Memory(void)387   FT_New_Memory( void )
388   {
389     FT_Memory  memory;
390 
391 
392     memory = (FT_Memory)malloc( sizeof ( *memory ) );
393     if ( memory )
394     {
395       memory->user    = 0;
396       memory->alloc   = ft_alloc;
397       memory->realloc = ft_realloc;
398       memory->free    = ft_free;
399 #ifdef FT_DEBUG_MEMORY
400       ft_mem_debug_init( memory );
401 #endif
402     }
403 
404     return memory;
405   }
406 
407 
408   /* documentation is in ftobjs.h */
409 
410   FT_BASE_DEF( void )
FT_Done_Memory(FT_Memory memory)411   FT_Done_Memory( FT_Memory  memory )
412   {
413 #ifdef FT_DEBUG_MEMORY
414     ft_mem_debug_done( memory );
415 #endif
416     memory->free( memory, memory );
417   }
418 
419 
420 /* END */
421