shithub: freetype+ttf2subf

ref: 5ae1259c038d35255fb0331f3a413681df550ba2
dir: /config/ansi/ftsys.c/

View raw version
/***************************************************************************/
/*                                                                         */
/*  ftsys.c                                                                */
/*                                                                         */
/*    ANSI-specific system operations (body).                              */
/*                                                                         */
/*  Copyright 1996-1999 by                                                 */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used        */
/*  modified and distributed under the terms of the FreeType project       */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/


  /*************************************************************************/
  /*                                                                       */
  /* This implementation of the `ftsys' component uses the standard ANSI C */
  /* library.                                                              */
  /*                                                                       */
  /* IMPORTANT NOTE:                                                       */
  /*                                                                       */
  /*    Porters, read carefully the comments in ftsys.h before trying to   */
  /*    port this file to your system.  It contains many essential         */
  /*    remarks, and will ease your work greatly.                          */
  /*                                                                       */
  /*************************************************************************/


#include "ftsys.h"
#include "ftstream.h"
#include "ftdebug.h"


#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
#include "memdebug.c"
#endif


  /*************************************************************************/
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  /* parameter of the PTRACE() and PERROR() macros, used to print/log      */
  /* messages during execution.                                            */
  /*                                                                       */
#undef  FT_COMPONENT
#define FT_COMPONENT  trace_io


#undef  CUR_SYSTEM  /* just in case */


  /*************************************************************************/
  /*                                                                       */
  /* To ease porting, we use the macro SYS_STREAM to name the              */
  /* system-specific stream type.  For example, it is a `FILE*' with the   */
  /* ANSI libc, it will be a file descriptor, i.e. an integer, when using  */
  /* the Unix system API, etc.                                             */
  /*                                                                       */
#define SYS_STREAM  FILE*


  /*************************************************************************/
  /*                                                                       */
  /* This implementation of ftsys uses the ANSI C library.  Memory         */
  /* management is performed through malloc/free, i/o access through       */
  /* fopen/fread/fseek, and no synchronisation primitive is implemented    */
  /* (they contain dummy code)                                             */
  /*                                                                       */
  /*************************************************************************/


#include <stdio.h>
#include <stdlib.h>


  /*************************************************************************/
  /*                                                                       */
  /*                      I/O ACCESS AND MANAGEMENT                        */
  /*                                                                       */
  /* We only define the `ANSI' resource class in this class.  It is        */
  /* disk-based and provides a MRU cache in order to only keep the file    */
  /* descriptors of the 10 most recently used resource files.              */
  /*                                                                       */
  /* It simply contains two lists.  One contains the `cached' resources    */
  /* with a valid FILE* pointer, the second contains all other `flushed'   */
  /* resource objects.                                                     */
  /*                                                                       */
  /*************************************************************************/


  /*************************************************************************/
  /*                                                                       */
  /* <Struct>                                                              */
  /*    FT_AnsiFileRec                                                     */
  /*                                                                       */
  /* <Description>                                                         */
  /*    The FT_AnsiFile class derives from FT_ResourceRec.                 */
  /*                                                                       */
  /* <Fields>                                                              */
  /*    root      :: The root resource class fields.                       */
  /*                                                                       */
  /*    pathname  :: This is a copy of the ANSI file pathname used to open */
  /*                 streams for the resource.  A different implementation */
  /*                 is free to use Unicode chars, or file i-node numbers, */
  /*                 etc.                                                  */
  /*                                                                       */
  /*    file_size :: The size in bytes of the resource.  This field should */
  /*                 be set to -1 until the resource is first opened.      */
  /*                                                                       */
  typedef struct  FT_AnsiFileRec_
  {
    FT_ResourceRec  root;
    char*           pathname;   /* the font file's pathname           */
    FT_Long         file_size;  /* file size in bytes                 */

  } FT_AnsiFileRec, *FT_AnsiFile;


  /*************************************************************************/
  /*                                                                       */
  /* We use the macro STREAM_Name() as a convenience to return a given     */
  /* ANSI resource's pathname.  Its `stream' argument is a FT_Resource     */
  /* which is typecasted to the FT_AnsiFile class.                         */
  /*                                                                       */
#define STREAM_Name( stream )  ((FT_AnsiFile)stream->resource)->pathname


  /*************************************************************************/
  /*                                                                       */
  /* We use the macro STREAM_File() as a convenience to extract the        */
  /* system-specific stream handle from a given FreeType stream object.    */
  /*                                                                       */
#define STREAM_File( stream )  ((FILE*)stream->stream_id.pointer)


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    AnsiFile_Open                                                      */
  /*                                                                       */
  /* <Description>                                                         */
  /*    This function is used to open a system-stream for a given          */
  /*    resource.                                                          */
  /*                                                                       */
  /*    Note that it must update the target FreeType stream object with    */
  /*    the system-stream handle and the resource's size.                  */
  /*                                                                       */
  /*    Also, the `stream->base' field must be set to NULL for disk-based  */
  /*    resources, and to the address in memory of the resource's first    */
  /*    byte for memory-based ones.                                        */
  /*                                                                       */
  /* <Input>                                                               */
  /*    resource :: The source resource.                                   */
  /*    stream   :: The target stream object.                              */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  /* <Note>                                                                */
  /*    This function simply calls fopen() in the resource's file          */
  /*    pathname.                                                          */
  /*                                                                       */
  /*    The stream object IS NOT CREATED by this function, but by its      */
  /*    caller.                                                            */
  /*                                                                       */
  static
  FT_Error  AnsiFile_Open( FT_AnsiFile  resource,
                           FT_Stream    stream )
  {
    FILE*  file;

    /* open the file */
    file = fopen( resource->pathname, "rb" );
    if ( !file )
    {
      PERROR(( "AnsiFile_Open: Could not open file `%s'\n",
               resource->pathname ));
      return FT_Err_Cannot_Open_Stream;
    }

    /* compute file size if necessary */
    if ( resource->file_size < 0 )
    {
      fseek( file, 0, SEEK_END );
      resource->file_size = ftell( file );
      fseek( file, 0, SEEK_SET );
    }

    stream->resource          = (FT_Resource)resource;
    stream->stream_id.pointer = file;
    stream->size              = resource->file_size;

    /* it's a disk-based resource, we don't need to use the `base' and   */
    /* `cursor' fields of the stream objects                             */
    stream->base              = NULL;
    stream->cursor            = NULL;

    PTRACE1(( "AnsiFile_Open: Opened `%s' (%d bytes) successfully\n",
              resource->pathname, resource->file_size ));

    return FT_Err_Ok;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    AnsiFile_Close                                                     */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Closes a given stream.                                             */
  /*                                                                       */
  /* <Input>                                                               */
  /*    stream :: The target stream object.                                */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  /* <Note>                                                                */
  /*    This function simply calls fclose() on the stream's ANSI FILE      */
  /*    object.                                                            */
  /*                                                                       */
  static
  FT_Error  AnsiFile_Close( FT_Stream  stream )
  {
    PTRACE1(( "AnsiFile_Close: Closing file `%s'\n", STREAM_Name( stream ) ));

    fclose( STREAM_File( stream ) );

    stream->resource          = NULL;
    stream->stream_id.pointer = NULL;
    stream->size              = 0;

    return FT_Err_Ok;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    AnsiFile_Seek                                                      */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Seeks a stream to a given position.                                */
  /*                                                                       */
  /* <Input>                                                               */
  /*    stream   :: The target stream object.                              */
  /*    position :: The offset in bytes from the start of the              */
  /*                resource/stream.                                       */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  /* <Note>                                                                */
  /*    This function simply calls fseek() on the stream.                  */
  /*                                                                       */
  /*    The `seek' method is never called by the stream manager in case    */
  /*    of a memory-based resource (i.e., when `stream->base' isn't NULL). */
  /*                                                                       */
  static
  FT_Error  AnsiFile_Seek( FT_Stream  stream,
                           FT_Long    position )
  {
    if ( fseek( STREAM_File( stream ), position, SEEK_SET ) )
    {
      PERROR(( "AnsiFile_Seek: FAILED!  Pos. %ld of `%s'\n",
               position, STREAM_Name( stream ) ));

      return FT_Err_Invalid_Stream_Seek;
    }

    PTRACE2(( "AnsiFile_Seek: Pos. %ld of `%s'\n",
              position, STREAM_Name( stream ) ));

    return FT_Err_Ok;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    AnsiFile_Skip                                                      */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Skips a given number of bytes in an ANSI stream.  Useful to skip   */
  /*    pad bytes, for example.                                            */
  /*                                                                       */
  /* <Input>                                                               */
  /*    stream :: The target stream object.                                */
  /*    count  :: The number of bytes to skip in the stream.               */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  /* <Note>                                                                */
  /*    This function simply calls fseek() on the stream.                  */
  /*                                                                       */
  /*    The `skip' method is never called by the stream manager in case    */
  /*    of a memory-based resource (i.e., when `stream->base' isn't NULL). */
  /*                                                                       */
  static
  FT_Error  AnsiFile_Skip( FT_Stream  stream,
                           FT_Long    count )
  {
    if ( fseek( STREAM_File( stream ), count, SEEK_CUR ) )
    {
      PERROR(( "AnsiFile_Skip: FAILED!  %ld bytes in `%s'\n",
               count, STREAM_Name( stream ) ));

      return FT_Err_Invalid_Stream_Seek;
    }

    PTRACE2(( "AnsiFile_Skip: %ld bytes in `%s'\n",
              count, STREAM_Name( stream ) ));

    return FT_Err_Ok;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    AnsiFile_Pos                                                       */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Returns the current offset within an ANSI stream's resource.       */
  /*                                                                       */
  /* <Input>                                                               */
  /*    stream   :: The target stream object.                              */
  /*                                                                       */
  /* <Output>                                                              */
  /*    position :: The current offset.  -1 in case of error.              */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  /* <Note>                                                                */
  /*    This function simply calls ftell() on the stream.                  */
  /*                                                                       */
  /*    The `pos' method is never called by the stream manager in case     */
  /*    of a memory-based resource (i.e., when `stream->base' isn't NULL). */
  /*                                                                       */
  static
  FT_Error  AnsiFile_Pos( FT_Stream  stream,
                          FT_Long*   position )
  {
    *position = ftell( STREAM_File( stream ) );
    if ( *position == -1 )
    {
      PTRACE2(( "AnsiFile_Pos: FAILED!  In `%s'\n", STREAM_Name( stream ) ));
      return FT_Err_Invalid_Stream_Seek;
    }

    PTRACE2(( "AnsiFile_Pos: For `%s'\n", STREAM_Name( stream ) ));
    return FT_Err_Ok;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    AnsiFile_Read                                                      */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Reads a given number of bytes from an ANSI stream into memory.     */
  /*                                                                       */
  /* <Input>                                                               */
  /*    stream     :: The target stream object.                            */
  /*    buffer     :: The target read buffer where data is copied.         */
  /*    size       :: The number of bytes to read from the stream.         */
  /*                                                                       */
  /* <Output>                                                              */
  /*    read_bytes :: The number of bytes effectively read from the        */
  /*                  stream.  Used in case of error                       */
  /*                  (i.e. FT_Err_Invalid_Stream_Read) by some parts of   */
  /*                  the library.                                         */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  /* <Note>                                                                */
  /*   This function simply calls fread() on the stream.                   */
  /*                                                                       */
  /*   It MUST return the error FT_Err_Invalid_Stream_Read in case of      */
  /*   an over-read (i.e., reading more bytes from the stream that what    */
  /*   is left), as the stream component checks for this specific value.   */
  /*                                                                       */
  /*   The `read' method is never called by the stream manager in case     */
  /*   of a memory-based resource (i.e., when `stream->base' isn't NULL).  */
  /*                                                                       */
  static
  FT_Error  AnsiFile_Read( FT_Stream  stream,
                           FT_Char*   buffer,
                           FT_Long    size,
                           FT_Long*   read_bytes )
  {
    *read_bytes = fread( buffer, 1, size, STREAM_File( stream ) );
    if ( *read_bytes != size )
    {
      /* Note : we can have an over-read here when called by the */
      /*        function FT_Access_Compressed_Frame. This means  */
      /*        that the following message should be a trace,    */
      /*        rather than an error for disk-based resources..  */
      /*                                                         */
      /*        the function must set the value of 'read_bytes'  */
      /*        even if it returns an error code..               */
      PTRACE2(( "AnsiFile_Read: FAILED!  Read %ld bytes from '%s'\n",
               size, STREAM_Name( stream ) ));

      return FT_Err_Invalid_Stream_Read;
    }

    PTRACE2(( "AnsiFile_Read: Read %ld bytes to buffer 0x%08lx from `%s'\n",
              size, (long)buffer, STREAM_Name( stream ) ));
    return FT_Err_Ok;
  }


  /*************************************************************************/
  /*                                                                       */
  /* The following table is the `virtual method table' for the `ANSI       */
  /* resource class', which methods are defined above.  Its address is set */
  /* in the `interface' field of all resource objects created by the       */
  /* function FT_Create_AnsiFile() (see below).                            */
  /*                                                                       */
  static
  FTRes_InterfaceRec  FT_AnsiFile_Interface =
  {
    (FTRes_Open_Func) AnsiFile_Open,
    (FTRes_Close_Func)AnsiFile_Close,
    (FTRes_Seek_Func) AnsiFile_Seek,
    (FTRes_Skip_Func) AnsiFile_Skip,
    (FTRes_Pos_Func)  AnsiFile_Pos,
    (FTRes_Read_Func) AnsiFile_Read,
  };


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    FT_Create_Resource                                                 */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Creates a new resource object.  This function is called by the     */
  /*    FT_New_Resource() function of the base layer.                      */
  /*                                                                       */
  /* <Input>                                                               */
  /*    library   :: The input library object.                             */
  /*    pathname  :: The file's pathname as an ASCII string.               */
  /*                                                                       */
  /* <Output>                                                              */
  /*    aresource :: A handle to new resource object.                      */
  /*                                                                       */
  /* <Return>                                                              */
  /*    Error code.  0 means success.                                      */
  /*                                                                       */
  /* <Note>                                                                */
  /*    This functions does not open a stream.  It simply copies the       */
  /*    pathname within a fresh new resource object.                       */
  /*                                                                       */
  EXPORT_FUNC
  FT_Error  FT_Create_Resource( FT_Library    library,
                                const char*   pathname,
                                FT_Resource*  aresource )
  {
    FT_Int       len;
    FT_AnsiFile  resource;
    FT_Error     error;
    FT_System    system;


    if ( !library )
      return FT_Err_Invalid_Library_Handle;

    system = library->system;

    if ( !pathname )
      goto Fail_Null;

    len = strlen( pathname );
    if ( len == 0 )
      goto Fail_Null;

    resource = NULL;

    if ( ALLOC( resource, sizeof ( *resource ) ) ||
         ALLOC( resource->pathname, len + 1 )    )
      goto Fail_Memory;

    resource->root.library   = library;
    resource->root.interface = &FT_AnsiFile_Interface;
    resource->root.flags     = FT_RESOURCE_TYPE_DISK_BASED;
    resource->file_size      = -1;
    strcpy( resource->pathname, pathname );

    PTRACE1(( "Create_AnsiFile: Ansi resource created for `%s'\n",
              pathname ));

    *aresource = (FT_Resource)resource;
    return FT_Err_Ok;

  Fail_Null:
    PERROR(( "Create_AnsiFile: Null pathname!\n" ));
    return FT_Err_Invalid_Argument;

  Fail_Memory:
    if ( resource )
      FREE( resource->pathname );
    FREE( resource );
    PERROR(( "Create_AnsiFile: Not enough memory to create resource!\n" ));
    return error;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    FT_Destroy_Resource                                                */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Discards a given resource object explicitly.                       */
  /*                                                                       */
  /* <Input>                                                               */
  /*    resource :: The ANSI resource object.                              */
  /*                                                                       */
  /* <Note>                                                                */
  /*    This function does not check whether runs or streams are opened    */
  /*    for the resource (for now, we assume developer intelligence.       */
  /*    We'll most probably lower our standard later to ease debugging :-) */
  /*                                                                       */
  EXPORT_FUNC
  FT_Error  FT_Destroy_Resource( FT_Resource  resource )
  {
    FT_System    system = resource->library->system;
    FT_AnsiFile  ansi   = (FT_AnsiFile)resource;

    if ( !ansi || ansi->root.interface != &FT_AnsiFile_Interface )
    {
      PERROR((
        "Destroy_AnsiFile: Trying to destroy an invalid resource!\n" ));
      return FT_Err_Invalid_Resource_Handle;
    }

    PTRACE1(( "Destroy_AnsiFile: Destroying resource for `%s'\n",
              ansi->pathname ));

    FREE( ansi->pathname );
    FREE( ansi );

    return FT_Err_Ok;
  }


  /*************************************************************************/
  /*                                                                       */
  /*                          MEMORY MANAGEMENT                            */
  /*                                                                       */
  /*                                                                       */
  /*  This part copies the old FreeType 1.0 and 1.1 memory management      */
  /*  scheme that was defined in the file `ttmemory.h'.  One can see that  */
  /*                                                                       */
  /*  - a set of macros is defined for the memory operations used by the   */
  /*    engine (MEM_Copy(), MEM_Move(), MEM_Set()).  This comes from the   */
  /*    fact that many compilers are able to inline these operations       */
  /*    directly within the compiled code, rather than generating a call   */
  /*    to the C library.  However, this obliges us to include the         */
  /*    `<string.h>' header file.                                          */
  /*                                                                       */
  /*    If you provide your own memory operations, you can get rid of the  */
  /*    `#include <string.h>' below.                                       */
  /*                                                                       */
  /*                                                                       */
  /*  - the FT_Alloc() function has several essential properties that MUST */
  /*    be retained by each port:                                          */
  /*                                                                       */
  /*    - It returns an error code, NOT the allocated block's base         */
  /*      address.                                                         */
  /*                                                                       */
  /*    - It takes the address of a target pointer, where the block's base */
  /*      address will be set.  If the size is zero, its value will be     */
  /*      NULL, and the function returns successfully.                     */
  /*                                                                       */
  /*    - In case of error, the pointer's value is set to NULL and an      */
  /*      error code is returned.                                          */
  /*                                                                       */
  /*    - The new allocated block MUST be zero-filled.  This is a strong   */
  /*      convention the rest of the engine relies on.                     */
  /*                                                                       */
  /*                                                                       */
  /*  - the FT_Free() function has also its essentials:                    */
  /*                                                                       */
  /*    - It takes the address of a pointer which value is the block's     */
  /*      base address.  This is UNLIKE a standard `free()' which takes    */
  /*      the block's base directly.                                       */
  /*                                                                       */
  /*    - It accepts successfully the address of a pointer which value is  */
  /*      NULL, in which case it simply returns.                           */
  /*                                                                       */
  /*    - The pointer is always set to NULL by the function.               */
  /*                                                                       */
  /*                                                                       */
  /*  - The MEM_Alloc(), ALLOC(), and ALLOC_ARRAY() macros are used by the */
  /*    library and should NOT be modified by porters!                     */
  /*                                                                       */
  /*************************************************************************/


  /*************************************************************************/
  /*                                                                       */
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  /* parameter of the PTRACE() and PERROR() macros, used to print/log      */
  /* messages during execution.                                            */
  /*                                                                       */
#undef  FT_COMPONENT
#define FT_COMPONENT  trace_memory


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    FT_Alloc                                                           */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Allocates a new block of memory.  The returned area is always      */
  /*    zero-filled, this is a strong convention in many FreeType parts.   */
  /*                                                                       */
  /* <Input>                                                               */
  /*    system :: A handle to a given `system object' where allocation     */
  /*              occurs.                                                  */
  /*                                                                       */
  /*    size   :: The size in bytes of the block to allocate.              */
  /*                                                                       */
  /* <Output>                                                              */
  /*    P      :: A pointer to the fresh new block.  It should be set to   */
  /*              NULL if `size' is 0, or in case of error.                */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  BASE_FUNC
  FT_Error  FT_Alloc( FT_System  system,
                      FT_Long    size,
                      void**     P )
  {
    if ( !P )
    {
      PERROR(( "FT_Alloc: Invalid pointer address!\n" ));
      return FT_Err_Invalid_Argument;
    }

    if ( size > 0 )
    {
      *P = malloc( size );
      if ( !*P )
      {
        PERROR(( "FT_Alloc: Out of memory (%ld bytes requested)!\n",
                 size ));

        return FT_Err_Out_Of_Memory;
      }

#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
      DM_Record( (char*)*P, size );
#endif

      system->total_alloc += size;

      /* ALWAYS ZERO-FILL THE BLOCK! */
      MEM_Set( *P, 0, size );
    }
    else
      *P = NULL;

    PTRACE2(( "FT_Alloc: Size = %ld, pointer = 0x%08lx, block = 0x%08lx\n",
              size, (long)P, (long)*P ));

    return FT_Err_Ok;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    FT_Realloc                                                         */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Reallocates a block of memory pointed to by `*P' to `Size' bytes   */
  /*    from the heap, possibly changing `*P'.                             */
  /*                                                                       */
  /* <Input>                                                               */
  /*    system :: A handle to a given `system object' where allocation     */
  /*              occurs.                                                  */
  /*                                                                       */
  /*    size   :: The size in bytes of the block to allocate.              */
  /*                                                                       */
  /* <InOut>                                                               */
  /*    P      :: A pointer to the fresh new block.  It should be set to   */
  /*              NULL if `size' is 0, or in case of error.                */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  BASE_FUNC
  FT_Error  FT_Realloc( FT_System  system,
                        FT_Long    size,
                        void*     *P )
  {
    void*  Q;


    if ( !P )
    {
      PERROR(( "FT_Realloc: Invalid pointer address!\n" ));
      return FT_Err_Invalid_Argument;
    }

    /* if the original pointer is NULL, call FT_Alloc() */
    if ( !*P )
      return FT_Alloc( system, size, P );

    /* if the new block if zero-sized, clear the current one */
    if ( size <= 0 )
      return FT_Free( system, P );

#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
    DM_Forget( (char*)*P );
#endif

    Q = (void*)realloc( *P, size );
    if ( !Q )
    {
      PERROR(( "FT_Realloc: Reallocation failed!\n" ));
      return FT_Err_Out_Of_Memory;
    }

#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
    DM_Record( (char*)Q, size );
#endif

    *P = Q;
    return FT_Err_Ok;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    FT_Free                                                            */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Releases a given block of memory allocated through FT_Alloc().     */
  /*                                                                       */
  /* <Input>                                                               */
  /*    system :: A handle to a given `system object' where allocation     */
  /*              occured.                                                 */
  /*                                                                       */
  /*    P      :: This is the _address_ of a _pointer_ which points to the */
  /*              allocated block.  It is always set to NULL on exit.      */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  /* <Note>                                                                */
  /*    If P or *P are NULL, this function should return successfully.     */
  /*    This is a strong convention within all of FreeType and its         */
  /*    drivers.                                                           */
  /*                                                                       */
  BASE_FUNC
  FT_Error  FT_Free( FT_System  system,
                     void*     *P )
  {
    UNUSED( system );

    PTRACE2(( "FT_Free: Freeing pointer 0x%08lx (block 0x%08lx)\n",
              (long)P, (P ? (long)*P : -1) ));

    if ( !P || !*P )
      return FT_Err_Ok;

    free( *P );

#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
    DM_Forget( (char*)*P );
#endif

    *P = NULL;

    return FT_Err_Ok;
  }


  /*************************************************************************/
  /*                                                                       */
  /*                       SYNCHRONIZATION MANAGEMENT                      */
  /*                                                                       */
  /*                                                                       */
  /*   This section deals with mutexes.  The library can be compiled to    */
  /*   two distinct thread support levels (namely single threaded and      */
  /*   re-entrant modes).                                                  */
  /*                                                                       */
  /*   It protects its variables through the MUTEX_Lock() and              */
  /*   MUTEX_Release() macros which are void in single threaded mode.      */
  /*                                                                       */
  /*   It defines a typeless mutex reference type, `FT_Mutex', that you're */
  /*   free to redefine for your system's needs.                           */
  /*                                                                       */
  /*   The default implementation of ftsys.c contains only dummy functions */
  /*   which always return successfully.  You NEED to specialize them in   */
  /*   order to port ftsys.c to any multi-threaded environment.            */
  /*                                                                       */
  /*************************************************************************/


  /*************************************************************************/
  /*                                                                       */
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  /* parameter of the PTRACE() and PERROR() macros, used to print/log      */
  /* messages during execution.                                            */
  /*                                                                       */
#undef  FT_COMPONENT
#define FT_COMPONENT  trace_sync


#ifdef FT_CONFIG_THREADS

  BASE_FUNC
  FT_Error  FT_Mutex_Create( FT_System  system,
                             TMutex*    mutex )
  {
    UNUSED( system );

    mutex = (void*)-1;
    system->num_mutexes++;

    /* Insert your own mutex creation code here */

    return FT_Err_Ok;
  }


  BASE_FUNC
  void  FT_Mutex_Delete( FT_System  system,
                         TMutex*    mutex )
  {
    UNUSED( system );

    mutex = (void*)0;
    system->num_mutexes--;

    /* Insert your own mutex destruction code here */
  }


  BASE_FUNC
  void  FT_Mutex_Lock( FT_System  system,
                       TMutex*    mutex )
  {
    /* NOTE: It is legal to call this function with a NULL argument */
    /*       in which case an immediate return is appropriate.      */

    UNUSED( system );

    if ( !mutex )
      return;

    /* Insert your own mutex locking code here */
  }


  BASE_FUNC
  void  FT_Mutex_Release( FT_System  system,
                          TMutex*    mutex )
  {
    /* NOTE: It is legal to call this function with a NULL argument */
    /*       in which case an immediate return is appropriate       */

    UNUSED( system );

    if ( !mutex )
      return;

    /* Insert your own mutex release code here */
  }

#endif /* FT_CONFIG_THREADS */


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    FT_New_System                                                      */
  /*                                                                       */
  /* <Description>                                                         */
  /*    This function is used to create and initialize new system objects. */
  /*    These are mainly used to let client applications and font servers  */
  /*    specify their own memory allocators and synchronization            */
  /*    procedures.                                                        */
  /*                                                                       */
  /* <Output>                                                              */
  /*    system :: A handle to a given `system object'.                     */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  EXPORT_FUNC
  FT_Error  FT_New_System( FT_System*  system )
  {
    *system = (FT_System)malloc( sizeof ( **system ) );

    if ( !*system )
      return FT_Err_Out_Of_Memory;

    /* the ANSI function `free()' is unable to return the number   */
    /* of released bytes.  Hence, the `current_alloc' field of the */
    /* system object cannot be used.                               */

    (*system)->system_flags = FT_SYSTEM_FLAG_TOTAL_ALLOC |
                              FT_SYSTEM_FLAG_MUTEXES;
    (*system)->total_alloc = 0;
    (*system)->num_mutexes = 0;

#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
    DM_Init_Mem();
#endif

    /* initialize i/o management (nothing) */

    /* initialize synchronisation (nothing) */

    /* initialize streams (nothing) */

    return FT_Err_Ok;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    FT_Done_System                                                     */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Destroys a given FreeType system object.                           */
  /*                                                                       */
  /* <Input>                                                               */
  /*    system :: A handle to a given `system object'.                     */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  EXPORT_FUNC
  FT_Error  FT_Done_System( FT_System  system )
  {
    /* finalize synchronization (nothing) */

    /* finalize i/o management (nothing) */

    /* finalize memory management */

#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
    DM_Done_Mem();
#endif

    free( system );

    return FT_Err_Ok;
  }


/* END */