/*******************************************************************
 *
 *  ttfile.h                                                     1.4
 *
 *    File I/O Component (specification).
 *
 *  Copyright 1996-2002 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.
 *
 *  Changes between 1.4 and 1.2 :
 *
 *  - the macros which used to be in ttload.h are now here
 *    (with their underlying functions)
 *
 *  Changes between 1.3 and 1.2:
 *
 *  - all functions report error values now
 *
 *  - the stream semantics have also changed
 *
 *  Changes between 1.2 and 1.1:
 *
 *  - added macros to support re-entrant builds
 *
 *  - added the TT_Duplicate_File function to duplicate streams
 *    (re-entrant builds only)
 *
 ******************************************************************/

#ifndef TTFILE_H
#define TTFILE_H

#include "ttconfig.h"
#include "freetype.h"
#include "ttengine.h"
#include "ttdebug.h"

#ifdef __cplusplus
  extern "C" {
#endif

  /* Initialize file component */
  FT_INTERNAL_DEF( TT_Error )
  TTFile_Init( PEngine_Instance  engine );

  /* Done with file component */
  FT_INTERNAL_DEF( TT_Error )
  TTFile_Done( PEngine_Instance  engine );


  /****************************************************************/
  /*                                                              */
  /*  Macros.                                                     */
  /*                                                              */
  /****************************************************************/

/* The following macros are defined to simplify the writing of */
/* the various table and glyph loaders.                        */

/* For examples see the code in ttload.c, ttgload.c etc.       */

#define USE_Stream( original, duplicate ) \
          ( (error = TT_Use_Stream( original, &duplicate )) != TT_Err_Ok )

#define DONE_Stream( _stream ) \
          TT_Done_Stream( &_stream )

/* Define a file frame -- use it only when needed */
#define DEFINE_A_FRAME   TFileFrame  frame = TT_Null_FileFrame

/* Define a stream -- use it only when needed */
#define DEFINE_A_STREAM  TT_Stream   stream


#ifdef TT_CONFIG_OPTION_THREAD_SAFE  /* re-entrant implementation */

/* The following macros define the necessary local */
/* variables used to access streams and frames.    */

/* Define stream locals with frame */
#define DEFINE_STREAM_LOCALS  \
          TT_Error  error;    \
          DEFINE_A_STREAM;    \
          DEFINE_A_FRAME

/* Define stream locals without frame */
#define DEFINE_STREAM_LOCALS_WO_FRAME  \
          TT_Error  error;             \
          DEFINE_A_STREAM

/* Define locals with a predefined stream in reentrant mode -- see ttload.c */
#define DEFINE_LOAD_LOCALS( STREAM )  \
          TT_Error  error;            \
          DEFINE_A_STREAM = (STREAM); \
          DEFINE_A_FRAME

/* Define locals without frame with a predefined stream - see ttload.c */
#define DEFINE_LOAD_LOCALS_WO_FRAME( STREAM ) \
          TT_Error      error;                \
          DEFINE_A_STREAM = (STREAM)

/* Define all locals necessary to access a font file */
#define DEFINE_ALL_LOCALS  \
          TT_Error  error; \
          DEFINE_A_STREAM; \
          DEFINE_A_FRAME


#define ACCESS_Frame( _size_ ) \
          ( (error = TT_Access_Frame( stream, \
                                      &frame, \
                                      (Long)(_size_) )) != TT_Err_Ok )
#define CHECK_AND_ACCESS_Frame( _size_ ) \
          ( (error = TT_Check_And_Access_Frame( stream, \
                                                &frame, \
                                                (Long)(_size_) )) != TT_Err_Ok )
#define FORGET_Frame() \
          ( (void)TT_Forget_Frame( stream, &frame ) )

#define GET_Byte()    TT_Get_Byte  ( &frame )
#define GET_Char()    TT_Get_Char  ( &frame )
#define GET_UShort()  TT_Get_UShort( &frame )
#define GET_Short()   TT_Get_Short ( &frame )
#define GET_Long()    TT_Get_Long  ( &frame )
#define GET_ULong()   TT_Get_ULong ( &frame )
#define GET_Tag4()    TT_Get_ULong ( &frame )

#define FILE_Pos()    TT_File_Pos ( stream )

#define FILE_Seek( _position_ ) \
          ( (error = TT_Seek_File( stream, \
                                   (Long)(_position_) )) != TT_Err_Ok )
#define FILE_Skip( _distance_ ) \
          ( (error = TT_Skip_File( stream, \
                                   (Long)(_distance_) )) != TT_Err_Ok )
#define FILE_Read( buffer, count ) \
          ( (error = TT_Read_File ( stream, \
                                    buffer, \
                                    (Long)(count) )) != TT_Err_Ok )
#define FILE_Read_At( pos, buffer, count ) \
          ( (error = TT_Read_At_File( stream, \
                                      (Long)(pos), \
                                      buffer, \
                                      (Long)(count) )) != TT_Err_Ok )

#else   /* thread-safe implementation */

/* Define stream locals with frame -- nothing in thread-safe mode */
#define DEFINE_STREAM_LOCALS  \
          TT_Error  error

/* Define stream locals without frame -- nothing in thread-safe mode */
#define DEFINE_STREAM_LOCALS_WO_FRAME \
          TT_Error  error

/* Define locals with a predefined stream in reentrant mode -- see ttload.c */
#define DEFINE_LOAD_LOCALS( STREAM ) \
          TT_Error  error


/* Define locals without frame with a predefined stream - see ttload.c */
#define DEFINE_LOAD_LOCALS_WO_FRAME( STREAM ) \
          TT_Error  error

/* Define all locals necessary to access a font file */
#define DEFINE_ALL_LOCALS  \
          TT_Error  error; \
          DEFINE_A_STREAM


#define ACCESS_Frame( _size_ ) \
          ( (error = TT_Access_Frame( (Long)(_size_) )) != TT_Err_Ok )
#define CHECK_AND_ACCESS_Frame( _size_ ) \
          ( (error = TT_Check_And_Access_Frame( (Long)(_size_) )) != TT_Err_Ok )
#define FORGET_Frame() \
          ( (void)TT_Forget_Frame() )

#define GET_Byte()    TT_Get_Byte  ()
#define GET_Char()    TT_Get_Char  ()
#define GET_UShort()  TT_Get_UShort()
#define GET_Short()   TT_Get_Short ()
#define GET_Long()    TT_Get_Long  ()
#define GET_ULong()   TT_Get_ULong ()
#define GET_Tag4()    TT_Get_ULong ()

#define FILE_Pos()    TT_File_Pos()

#define FILE_Seek( _position_ ) \
          ( (error = TT_Seek_File( (Long)(_position_) )) != TT_Err_Ok )
#define FILE_Skip( _distance_ ) \
          ( (error = TT_Skip_File( (Long)(_distance_) )) != TT_Err_Ok )
#define FILE_Read( buffer, count ) \
          ( (error = TT_Read_File ( buffer, \
                                    (Long)(count) )) != TT_Err_Ok )
#define FILE_Read_At( pos, buffer, count ) \
          ( (error = TT_Read_At_File( (Long)(pos), \
                                      buffer, \
                                      (Long)(count) )) != TT_Err_Ok )

#endif /* TT_CONFIG_OPTION_THREAD_SAFE */


  /****************************************************************/
  /*                                                              */
  /*  Stream functions.                                           */
  /*                                                              */
  /****************************************************************/

  /* Open a file and return a stream handle for it.           */
  /* Should only be used for a new face object's main stream. */

  FT_INTERNAL_DEF( TT_Error )
  TT_Open_Stream( const TT_Text* name,
                  TT_Stream*     stream );


  /* Closes, then discards, a stream when it's no longer needed.   */
  /* Should only be used for a stream opend with TT_Open_Stream(). */

  FT_INTERNAL_DEF( TT_Error )
  TT_Close_Stream( TT_Stream*  stream );


  /* Informs the component that we're going to use the file   */
  /* opened in 'org_stream', and report errors to the 'error' */
  /* variable.                                                */

  /* in non re-entrant builds, 'org_stream' is simply copied   */
  /* to 'stream'. Otherwise, the latter is a duplicate handle  */
  /* for the file opened with 'org_stream'                     */

  FT_EXPORT_DEF( TT_Error )
  TT_Use_Stream( TT_Stream   org_stream,
                 TT_Stream*  stream );

  /* Informs the component that we don't need to perform file */
  /* operations on the stream 'stream' anymore.  This must be */
  /* used with streams "opened" with TT_Use_Stream() only!    */

  /* in re-entrant builds, this will really discard the stream */

  FT_EXPORT_DEF( TT_Error )
  TT_Done_Stream( TT_Stream*  stream );

  /* Closes the stream's file handle to release system resources */
  /* The function TT_Use_Stream automatically re-activates a     */
  /* flushed stream when it uses one                             */

  FT_EXPORT_DEF( TT_Error )
  TT_Flush_Stream( TT_Stream*  stream );

/* The macros STREAM_ARGS and STREAM_ARG let us build a thread-safe */
/* or re-entrant implementation depending on a single configuration */
/*define.                                                           */

#ifdef TT_CONFIG_OPTION_THREAD_SAFE

#define STREAM_ARGS   TT_Stream  stream,
#define STREAM_ARG    TT_Stream  stream

#else

#define STREAM_ARGS   /* void */
#define STREAM_ARG    void

#endif /* TT_CONFIG_OPTION_THREAD_SAFE */


  /****************************************************************/
  /*                                                              */
  /*  File Functions.                                             */
  /*                                                              */
  /*  The following functions perform file operations on the      */
  /*  currently 'used' stream.  In thread-safe builds, only one   */
  /*  stream can be used at a time.  Synchronisation is performed */
  /*  through the Use_Stream()/Done_Stream() functions.           */
  /*                                                              */
  /****************************************************************/

  /* Read 'count' bytes from file into 'buffer' */

  FT_EXPORT_DEF( TT_Error )
  TT_Read_File( STREAM_ARGS void*   buffer,
                            Long    count );


  /* Seek file cursor to a given position */

  FT_EXPORT_DEF( TT_Error )
  TT_Seek_File( STREAM_ARGS Long  position );


  /* Skip the next 'distance' bytes in file */

  FT_EXPORT_DEF( TT_Error )
  TT_Skip_File( STREAM_ARGS Long  distance );


  /* Read the 'count' bytes at 'position' into 'buffer' */

  FT_EXPORT_DEF( TT_Error )
  TT_Read_At_File( STREAM_ARGS Long   position,
                               void*  buffer,
                               Long   count );

  /* Return current file position */

  FT_EXPORT_DEF( Long )
  TT_File_Pos( STREAM_ARG );

  /* Return length of a given stream, even if it is flushed */

  FT_EXPORT_DEF( Long )
  TT_Stream_Size( TT_Stream  stream );


  /****************************************************************/
  /*                                                              */
  /*  Frame operations.                                           */
  /*                                                              */
  /*  For a comprehensive explanation of frames, please refer to  */
  /*  the documentation files.                                    */
  /*                                                              */
  /****************************************************************/

  /* Frame type declaration.*/

  struct  TFileFrame_
  {
    Byte*  address;  /* frame buffer                     */
    Byte*  cursor;   /* current cursor position in frame */
    Long   size;     /* frame size                       */
  };

  typedef struct TFileFrame_  TFileFrame;

  FT_EXPORT_DECL( const TFileFrame )
        TT_Null_FileFrame;


/* The macro ZERO_Frame is used to define and init a frame.      */
/* It is important to have a default frame of { NULL, NULL, 0 }  */
/* before a call to TT_Access_Frame().  Otherwise, the call will */
/* fail with a TT_Err_Nested_Frame_Accesses error.               */

#define ZERO_Frame( frame )     \
      {                         \
        (frame).address = NULL; \
        (frame).cursor  = NULL; \
        (frame).size    = 0;    \
      }


/* The macros FRAME_ARGS and FRAME_ARG let us build a thread-safe   */
/* or re-entrant implementation depending on a single configuration */
/* define                                                           */

#ifdef TT_CONFIG_OPTION_THREAD_SAFE

#define FRAME_ARGS   TFileFrame*  frame,
#define FRAME_ARG    TFileFrame*  frame

#else

#define FRAME_ARGS   /* void */
#define FRAME_ARG    void

#endif /* TT_CONFIG_OPTION_THREAD_SAFE */


  /* Access the next 'size' bytes from current position. */
  /* Fails if all bytes cannot be read/accessed.         */

  FT_EXPORT_DEF( TT_Error )
  TT_Access_Frame( STREAM_ARGS FRAME_ARGS Long  size );


  /* Access the bytes located in the next 'size' bytes of the file. */
  /* Doesn't fail if less than 'size' bytes are accessible (like    */
  /* at the end of the file).                                       */

  FT_EXPORT_DEF( TT_Error )
  TT_Check_And_Access_Frame( STREAM_ARGS FRAME_ARGS Long  size );

  /* Forget frame */

  FT_EXPORT_DEF( TT_Error )
  TT_Forget_Frame( STREAM_ARGS FRAME_ARG );


  /* primitive routines for data accessing */

  FT_EXPORT_DEF( Char )
  TT_Get_Char(  FRAME_ARG );

  FT_EXPORT_DEF( Short )
  TT_Get_Short( FRAME_ARG );

  FT_EXPORT_DEF( Long  )
  TT_Get_Long(  FRAME_ARG );

#ifdef TT_CONFIG_OPTION_THREAD_SAFE

#define  TT_Get_Byte( frame )   ( (Byte  )TT_Get_Char ( frame ) )
#define  TT_Get_UShort( frame ) ( (UShort)TT_Get_Short( frame ) )
#define  TT_Get_ULong( frame )  ( (ULong )TT_Get_Long ( frame ) )

#else

#define  TT_Get_Byte()   ( (Byte  )TT_Get_Char () )
#define  TT_Get_UShort() ( (UShort)TT_Get_Short() )
#define  TT_Get_ULong()  ( (ULong )TT_Get_Long () )

#endif /* TT_CONFIG_OPTION_THREAD_SAFE */


#ifdef __cplusplus
  }
#endif

#endif /* TTFILE_H */


/* END */
