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