Home | History | Annotate | Download | only in unix
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  ftsystem.c                                                             */
      4 /*                                                                         */
      5 /*    Unix-specific FreeType low-level system interface (body).            */
      6 /*                                                                         */
      7 /*  Copyright 1996-2018 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 <ftconfig.h>
     22 #include FT_INTERNAL_DEBUG_H
     23 #include FT_SYSTEM_H
     24 #include FT_ERRORS_H
     25 #include FT_TYPES_H
     26 #include FT_INTERNAL_STREAM_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* )
     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* )
    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 )
    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  trace_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 )
    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 )
    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 )
    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' (%d 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 )
    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 )
    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