(root)/
freetype-2.13.2/
src/
gzip/
ftgzip.c
       1  /****************************************************************************
       2   *
       3   * ftgzip.c
       4   *
       5   *   FreeType support for .gz compressed files.
       6   *
       7   * This optional component relies on zlib.  It should mainly be used to
       8   * parse compressed PCF fonts, as found with many X11 server
       9   * distributions.
      10   *
      11   * Copyright (C) 2002-2023 by
      12   * David Turner, Robert Wilhelm, and Werner Lemberg.
      13   *
      14   * This file is part of the FreeType project, and may only be used,
      15   * modified, and distributed under the terms of the FreeType project
      16   * license, LICENSE.TXT.  By continuing to use, modify, or distribute
      17   * this file you indicate that you have read the license and
      18   * understand and accept it fully.
      19   *
      20   */
      21  
      22  
      23  #include <freetype/internal/ftmemory.h>
      24  #include <freetype/internal/ftstream.h>
      25  #include <freetype/internal/ftdebug.h>
      26  #include <freetype/ftgzip.h>
      27  #include FT_CONFIG_STANDARD_LIBRARY_H
      28  
      29  
      30  #include <freetype/ftmoderr.h>
      31  
      32  #undef FTERRORS_H_
      33  
      34  #undef  FT_ERR_PREFIX
      35  #define FT_ERR_PREFIX  Gzip_Err_
      36  #define FT_ERR_BASE    FT_Mod_Err_Gzip
      37  
      38  #include <freetype/fterrors.h>
      39  
      40  
      41  #ifdef FT_CONFIG_OPTION_USE_ZLIB
      42  
      43  #ifdef FT_CONFIG_OPTION_SYSTEM_ZLIB
      44  
      45  #include <zlib.h>
      46  
      47  #else /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */
      48  
      49    /* In this case, we include our own modified sources of the ZLib  */
      50    /* within the `gzip' component.  The modifications were necessary */
      51    /* to #include all files without conflicts, as well as preventing */
      52    /* the definition of `extern' functions that may cause linking    */
      53    /* conflicts when a program is linked with both FreeType and the  */
      54    /* original ZLib.                                                 */
      55  
      56  #ifndef USE_ZLIB_ZCALLOC
      57  #define MY_ZCALLOC /* prevent all zcalloc() & zfree() in zutil.c */
      58  #endif
      59  
      60    /* Note that our `zlib.h' includes `ftzconf.h' instead of `zconf.h'; */
      61    /* the main reason is that even a global `zlib.h' includes `zconf.h' */
      62    /* with                                                              */
      63    /*                                                                   */
      64    /*   #include "zconf.h"                                              */
      65    /*                                                                   */
      66    /* instead of the expected                                           */
      67    /*                                                                   */
      68    /*   #include <zconf.h>                                              */
      69    /*                                                                   */
      70    /* so that configuration with `FT_CONFIG_OPTION_SYSTEM_ZLIB' might   */
      71    /* include the wrong `zconf.h' file, leading to errors.              */
      72  
      73  #define ZEXPORT
      74    /* prevent zlib functions from being visible outside their object files */
      75  #define ZEXTERN  static
      76  
      77  #define HAVE_MEMCPY  1
      78  #define Z_SOLO       1
      79  #define Z_FREETYPE   1
      80  
      81  #if defined( _MSC_VER )      /* Visual C++ (and Intel C++)   */
      82    /* We disable the warning `conversion from XXX to YYY,     */
      83    /* possible loss of data' in order to compile cleanly with */
      84    /* the maximum level of warnings: zlib is non-FreeType     */
      85    /* code.                                                   */
      86  #pragma warning( push )
      87  #pragma warning( disable : 4244 )
      88  #endif /* _MSC_VER */
      89  
      90  #if defined( __GNUC__ )
      91  #pragma GCC diagnostic push
      92  #ifndef __cplusplus
      93  #pragma GCC diagnostic ignored "-Wstrict-prototypes"
      94  #endif
      95  #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
      96  #pragma GCC diagnostic ignored "-Wredundant-decls"
      97  #endif
      98  
      99  #include "zutil.c"
     100  #include "inffast.c"
     101  #include "inflate.c"
     102  #include "inftrees.c"
     103  #include "adler32.c"
     104  #include "crc32.c"
     105  
     106  #if defined( __GNUC__ )
     107  #pragma GCC diagnostic pop
     108  #endif
     109  
     110  #if defined( _MSC_VER )
     111  #pragma warning( pop )
     112  #endif
     113  
     114  #endif /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */
     115  
     116  
     117  /***************************************************************************/
     118  /***************************************************************************/
     119  /*****                                                                 *****/
     120  /*****            Z L I B   M E M O R Y   M A N A G E M E N T          *****/
     121  /*****                                                                 *****/
     122  /***************************************************************************/
     123  /***************************************************************************/
     124  
     125    /* it is better to use FreeType memory routines instead of raw
     126       'malloc/free' */
     127  
     128    static voidpf
     129    ft_gzip_alloc( voidpf  opaque,
     130                   uInt    items,
     131                   uInt    size )
     132    {
     133      FT_Memory   memory = (FT_Memory)opaque;
     134      FT_ULong    sz     = (FT_ULong)size * items;
     135      FT_Error    error;
     136      FT_Pointer  p      = NULL;
     137  
     138  
     139      /* allocate and zero out */
     140      FT_MEM_ALLOC( p, sz );
     141      return p;
     142    }
     143  
     144  
     145    static void
     146    ft_gzip_free( voidpf  opaque,
     147                  voidpf  address )
     148    {
     149      FT_Memory  memory = (FT_Memory)opaque;
     150  
     151  
     152      FT_MEM_FREE( address );
     153    }
     154  
     155  /***************************************************************************/
     156  /***************************************************************************/
     157  /*****                                                                 *****/
     158  /*****               Z L I B   F I L E   D E S C R I P T O R           *****/
     159  /*****                                                                 *****/
     160  /***************************************************************************/
     161  /***************************************************************************/
     162  
     163  #define FT_GZIP_BUFFER_SIZE  4096
     164  
     165    typedef struct  FT_GZipFileRec_
     166    {
     167      FT_Stream  source;         /* parent/source stream        */
     168      FT_Stream  stream;         /* embedding stream            */
     169      FT_Memory  memory;         /* memory allocator            */
     170      z_stream   zstream;        /* zlib input stream           */
     171  
     172      FT_ULong   start;          /* starting position, after .gz header */
     173      FT_Byte    input[FT_GZIP_BUFFER_SIZE];   /* input read buffer  */
     174  
     175      FT_Byte    buffer[FT_GZIP_BUFFER_SIZE];  /* output buffer      */
     176      FT_ULong   pos;                          /* position in output */
     177      FT_Byte*   cursor;
     178      FT_Byte*   limit;
     179  
     180    } FT_GZipFileRec, *FT_GZipFile;
     181  
     182  
     183    /* gzip flag byte */
     184  #define FT_GZIP_ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
     185  #define FT_GZIP_HEAD_CRC     0x02 /* bit 1 set: header CRC present */
     186  #define FT_GZIP_EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
     187  #define FT_GZIP_ORIG_NAME    0x08 /* bit 3 set: original file name present */
     188  #define FT_GZIP_COMMENT      0x10 /* bit 4 set: file comment present */
     189  #define FT_GZIP_RESERVED     0xE0 /* bits 5..7: reserved */
     190  
     191  
     192    /* check and skip .gz header - we don't support `transparent' compression */
     193    static FT_Error
     194    ft_gzip_check_header( FT_Stream  stream )
     195    {
     196      FT_Error  error;
     197      FT_Byte   head[4];
     198  
     199  
     200      if ( FT_STREAM_SEEK( 0 )       ||
     201           FT_STREAM_READ( head, 4 ) )
     202        goto Exit;
     203  
     204      /* head[0] && head[1] are the magic numbers;    */
     205      /* head[2] is the method, and head[3] the flags */
     206      if ( head[0] != 0x1F              ||
     207           head[1] != 0x8B              ||
     208           head[2] != Z_DEFLATED        ||
     209          (head[3] & FT_GZIP_RESERVED)  )
     210      {
     211        error = FT_THROW( Invalid_File_Format );
     212        goto Exit;
     213      }
     214  
     215      /* skip time, xflags and os code */
     216      (void)FT_STREAM_SKIP( 6 );
     217  
     218      /* skip the extra field */
     219      if ( head[3] & FT_GZIP_EXTRA_FIELD )
     220      {
     221        FT_UInt  len;
     222  
     223  
     224        if ( FT_READ_USHORT_LE( len ) ||
     225             FT_STREAM_SKIP( len )    )
     226          goto Exit;
     227      }
     228  
     229      /* skip original file name */
     230      if ( head[3] & FT_GZIP_ORIG_NAME )
     231        for (;;)
     232        {
     233          FT_UInt  c;
     234  
     235  
     236          if ( FT_READ_BYTE( c ) )
     237            goto Exit;
     238  
     239          if ( c == 0 )
     240            break;
     241        }
     242  
     243      /* skip .gz comment */
     244      if ( head[3] & FT_GZIP_COMMENT )
     245        for (;;)
     246        {
     247          FT_UInt  c;
     248  
     249  
     250          if ( FT_READ_BYTE( c ) )
     251            goto Exit;
     252  
     253          if ( c == 0 )
     254            break;
     255        }
     256  
     257      /* skip CRC */
     258      if ( head[3] & FT_GZIP_HEAD_CRC )
     259        if ( FT_STREAM_SKIP( 2 ) )
     260          goto Exit;
     261  
     262    Exit:
     263      return error;
     264    }
     265  
     266  
     267    static FT_Error
     268    ft_gzip_file_init( FT_GZipFile  zip,
     269                       FT_Stream    stream,
     270                       FT_Stream    source )
     271    {
     272      z_stream*  zstream = &zip->zstream;
     273      FT_Error   error   = FT_Err_Ok;
     274  
     275  
     276      zip->stream = stream;
     277      zip->source = source;
     278      zip->memory = stream->memory;
     279  
     280      zip->limit  = zip->buffer + FT_GZIP_BUFFER_SIZE;
     281      zip->cursor = zip->limit;
     282      zip->pos    = 0;
     283  
     284      /* check and skip .gz header */
     285      {
     286        stream = source;
     287  
     288        error = ft_gzip_check_header( stream );
     289        if ( error )
     290          goto Exit;
     291  
     292        zip->start = FT_STREAM_POS();
     293      }
     294  
     295      /* initialize zlib -- there is no zlib header in the compressed stream */
     296      zstream->zalloc = ft_gzip_alloc;
     297      zstream->zfree  = ft_gzip_free;
     298      zstream->opaque = stream->memory;
     299  
     300      zstream->avail_in = 0;
     301      zstream->next_in  = zip->buffer;
     302  
     303      if ( inflateInit2( zstream, -MAX_WBITS ) != Z_OK ||
     304           !zstream->next_in                           )
     305        error = FT_THROW( Invalid_File_Format );
     306  
     307    Exit:
     308      return error;
     309    }
     310  
     311  
     312    static void
     313    ft_gzip_file_done( FT_GZipFile  zip )
     314    {
     315      z_stream*  zstream = &zip->zstream;
     316  
     317  
     318      inflateEnd( zstream );
     319  
     320      /* clear the rest */
     321      zstream->zalloc    = NULL;
     322      zstream->zfree     = NULL;
     323      zstream->opaque    = NULL;
     324      zstream->next_in   = NULL;
     325      zstream->next_out  = NULL;
     326      zstream->avail_in  = 0;
     327      zstream->avail_out = 0;
     328  
     329      zip->memory = NULL;
     330      zip->source = NULL;
     331      zip->stream = NULL;
     332    }
     333  
     334  
     335    static FT_Error
     336    ft_gzip_file_reset( FT_GZipFile  zip )
     337    {
     338      FT_Stream  stream = zip->source;
     339      FT_Error   error;
     340  
     341  
     342      if ( !FT_STREAM_SEEK( zip->start ) )
     343      {
     344        z_stream*  zstream = &zip->zstream;
     345  
     346  
     347        inflateReset( zstream );
     348  
     349        zstream->avail_in  = 0;
     350        zstream->next_in   = zip->input;
     351        zstream->avail_out = 0;
     352        zstream->next_out  = zip->buffer;
     353  
     354        zip->limit  = zip->buffer + FT_GZIP_BUFFER_SIZE;
     355        zip->cursor = zip->limit;
     356        zip->pos    = 0;
     357      }
     358  
     359      return error;
     360    }
     361  
     362  
     363    static FT_Error
     364    ft_gzip_file_fill_input( FT_GZipFile  zip )
     365    {
     366      z_stream*  zstream = &zip->zstream;
     367      FT_Stream  stream  = zip->source;
     368      FT_ULong   size;
     369  
     370  
     371      if ( stream->read )
     372      {
     373        size = stream->read( stream, stream->pos, zip->input,
     374                             FT_GZIP_BUFFER_SIZE );
     375        if ( size == 0 )
     376        {
     377          zip->limit = zip->cursor;
     378          return FT_THROW( Invalid_Stream_Operation );
     379        }
     380      }
     381      else
     382      {
     383        size = stream->size - stream->pos;
     384        if ( size > FT_GZIP_BUFFER_SIZE )
     385          size = FT_GZIP_BUFFER_SIZE;
     386  
     387        if ( size == 0 )
     388        {
     389          zip->limit = zip->cursor;
     390          return FT_THROW( Invalid_Stream_Operation );
     391        }
     392  
     393        FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
     394      }
     395      stream->pos += size;
     396  
     397      zstream->next_in  = zip->input;
     398      zstream->avail_in = size;
     399  
     400      return FT_Err_Ok;
     401    }
     402  
     403  
     404    static FT_Error
     405    ft_gzip_file_fill_output( FT_GZipFile  zip )
     406    {
     407      z_stream*  zstream = &zip->zstream;
     408      FT_Error   error   = FT_Err_Ok;
     409  
     410  
     411      zip->cursor        = zip->buffer;
     412      zstream->next_out  = zip->cursor;
     413      zstream->avail_out = FT_GZIP_BUFFER_SIZE;
     414  
     415      while ( zstream->avail_out > 0 )
     416      {
     417        int  err;
     418  
     419  
     420        if ( zstream->avail_in == 0 )
     421        {
     422          error = ft_gzip_file_fill_input( zip );
     423          if ( error )
     424            break;
     425        }
     426  
     427        err = inflate( zstream, Z_NO_FLUSH );
     428  
     429        if ( err == Z_STREAM_END )
     430        {
     431          zip->limit = zstream->next_out;
     432          if ( zip->limit == zip->cursor )
     433            error = FT_THROW( Invalid_Stream_Operation );
     434          break;
     435        }
     436        else if ( err != Z_OK )
     437        {
     438          zip->limit = zip->cursor;
     439          error      = FT_THROW( Invalid_Stream_Operation );
     440          break;
     441        }
     442      }
     443  
     444      return error;
     445    }
     446  
     447  
     448    /* fill output buffer; `count' must be <= FT_GZIP_BUFFER_SIZE */
     449    static FT_Error
     450    ft_gzip_file_skip_output( FT_GZipFile  zip,
     451                              FT_ULong     count )
     452    {
     453      FT_Error  error = FT_Err_Ok;
     454  
     455  
     456      for (;;)
     457      {
     458        FT_ULong  delta = (FT_ULong)( zip->limit - zip->cursor );
     459  
     460  
     461        if ( delta >= count )
     462          delta = count;
     463  
     464        zip->cursor += delta;
     465        zip->pos    += delta;
     466  
     467        count -= delta;
     468        if ( count == 0 )
     469          break;
     470  
     471        error = ft_gzip_file_fill_output( zip );
     472        if ( error )
     473          break;
     474      }
     475  
     476      return error;
     477    }
     478  
     479  
     480    static FT_ULong
     481    ft_gzip_file_io( FT_GZipFile  zip,
     482                     FT_ULong     pos,
     483                     FT_Byte*     buffer,
     484                     FT_ULong     count )
     485    {
     486      FT_ULong  result = 0;
     487      FT_Error  error;
     488  
     489  
     490      /* Reset inflate stream if we're seeking backwards.        */
     491      /* Yes, that is not too efficient, but it saves memory :-) */
     492      if ( pos < zip->pos )
     493      {
     494        error = ft_gzip_file_reset( zip );
     495        if ( error )
     496          goto Exit;
     497      }
     498  
     499      /* skip unwanted bytes */
     500      if ( pos > zip->pos )
     501      {
     502        error = ft_gzip_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
     503        if ( error )
     504          goto Exit;
     505      }
     506  
     507      if ( count == 0 )
     508        goto Exit;
     509  
     510      /* now read the data */
     511      for (;;)
     512      {
     513        FT_ULong  delta;
     514  
     515  
     516        delta = (FT_ULong)( zip->limit - zip->cursor );
     517        if ( delta >= count )
     518          delta = count;
     519  
     520        FT_MEM_COPY( buffer, zip->cursor, delta );
     521        buffer      += delta;
     522        result      += delta;
     523        zip->cursor += delta;
     524        zip->pos    += delta;
     525  
     526        count -= delta;
     527        if ( count == 0 )
     528          break;
     529  
     530        error = ft_gzip_file_fill_output( zip );
     531        if ( error )
     532          break;
     533      }
     534  
     535    Exit:
     536      return result;
     537    }
     538  
     539  
     540  /***************************************************************************/
     541  /***************************************************************************/
     542  /*****                                                                 *****/
     543  /*****               G Z   E M B E D D I N G   S T R E A M             *****/
     544  /*****                                                                 *****/
     545  /***************************************************************************/
     546  /***************************************************************************/
     547  
     548    static void
     549    ft_gzip_stream_close( FT_Stream  stream )
     550    {
     551      FT_GZipFile  zip    = (FT_GZipFile)stream->descriptor.pointer;
     552      FT_Memory    memory = stream->memory;
     553  
     554  
     555      if ( zip )
     556      {
     557        /* finalize gzip file descriptor */
     558        ft_gzip_file_done( zip );
     559  
     560        FT_FREE( zip );
     561  
     562        stream->descriptor.pointer = NULL;
     563      }
     564  
     565      if ( !stream->read )
     566        FT_FREE( stream->base );
     567    }
     568  
     569  
     570    static unsigned long
     571    ft_gzip_stream_io( FT_Stream       stream,
     572                       unsigned long   offset,
     573                       unsigned char*  buffer,
     574                       unsigned long   count )
     575    {
     576      FT_GZipFile  zip = (FT_GZipFile)stream->descriptor.pointer;
     577  
     578  
     579      return ft_gzip_file_io( zip, offset, buffer, count );
     580    }
     581  
     582  
     583    static FT_ULong
     584    ft_gzip_get_uncompressed_size( FT_Stream  stream )
     585    {
     586      FT_Error  error;
     587      FT_ULong  old_pos;
     588      FT_ULong  result = 0;
     589  
     590  
     591      old_pos = stream->pos;
     592      if ( !FT_Stream_Seek( stream, stream->size - 4 ) )
     593      {
     594        result = FT_Stream_ReadULongLE( stream, &error );
     595        if ( error )
     596          result = 0;
     597  
     598        (void)FT_Stream_Seek( stream, old_pos );
     599      }
     600  
     601      return result;
     602    }
     603  
     604  
     605    /* documentation is in ftgzip.h */
     606  
     607    FT_EXPORT_DEF( FT_Error )
     608    FT_Stream_OpenGzip( FT_Stream  stream,
     609                        FT_Stream  source )
     610    {
     611      FT_Error     error;
     612      FT_Memory    memory;
     613      FT_GZipFile  zip = NULL;
     614  
     615  
     616      if ( !stream || !source )
     617      {
     618        error = FT_THROW( Invalid_Stream_Handle );
     619        goto Exit;
     620      }
     621  
     622      memory = source->memory;
     623  
     624      /*
     625       * check the header right now; this prevents allocating un-necessary
     626       * objects when we don't need them
     627       */
     628      error = ft_gzip_check_header( source );
     629      if ( error )
     630        goto Exit;
     631  
     632      FT_ZERO( stream );
     633      stream->memory = memory;
     634  
     635      if ( !FT_QNEW( zip ) )
     636      {
     637        error = ft_gzip_file_init( zip, stream, source );
     638        if ( error )
     639        {
     640          FT_FREE( zip );
     641          goto Exit;
     642        }
     643  
     644        stream->descriptor.pointer = zip;
     645      }
     646  
     647      /*
     648       * We use the following trick to try to dramatically improve the
     649       * performance while dealing with small files.  If the original stream
     650       * size is less than a certain threshold, we try to load the whole font
     651       * file into memory.  This saves us from using the 32KB buffer needed
     652       * to inflate the file, plus the two 4KB intermediate input/output
     653       * buffers used in the `FT_GZipFile' structure.
     654       */
     655      {
     656        FT_ULong  zip_size = ft_gzip_get_uncompressed_size( source );
     657  
     658  
     659        if ( zip_size != 0 && zip_size < 40 * 1024 )
     660        {
     661          FT_Byte*  zip_buff = NULL;
     662  
     663  
     664          if ( !FT_QALLOC( zip_buff, zip_size ) )
     665          {
     666            FT_ULong  count;
     667  
     668  
     669            count = ft_gzip_file_io( zip, 0, zip_buff, zip_size );
     670            if ( count == zip_size )
     671            {
     672              ft_gzip_file_done( zip );
     673              FT_FREE( zip );
     674  
     675              stream->descriptor.pointer = NULL;
     676  
     677              stream->size  = zip_size;
     678              stream->pos   = 0;
     679              stream->base  = zip_buff;
     680              stream->read  = NULL;
     681              stream->close = ft_gzip_stream_close;
     682  
     683              goto Exit;
     684            }
     685  
     686            ft_gzip_file_io( zip, 0, NULL, 0 );
     687            FT_FREE( zip_buff );
     688          }
     689          error = FT_Err_Ok;
     690        }
     691  
     692        if ( zip_size )
     693          stream->size = zip_size;
     694        else
     695          stream->size  = 0x7FFFFFFFL;  /* don't know the real size! */
     696      }
     697  
     698      stream->pos   = 0;
     699      stream->base  = NULL;
     700      stream->read  = ft_gzip_stream_io;
     701      stream->close = ft_gzip_stream_close;
     702  
     703    Exit:
     704      return error;
     705    }
     706  
     707  
     708    /* documentation is in ftgzip.h */
     709  
     710    FT_EXPORT_DEF( FT_Error )
     711    FT_Gzip_Uncompress( FT_Memory       memory,
     712                        FT_Byte*        output,
     713                        FT_ULong*       output_len,
     714                        const FT_Byte*  input,
     715                        FT_ULong        input_len )
     716    {
     717      z_stream  stream;
     718      int       err;
     719  
     720  
     721      /* check for `input' delayed to `inflate' */
     722  
     723      if ( !memory || !output_len || !output )
     724        return FT_THROW( Invalid_Argument );
     725  
     726      /* this function is modeled after zlib's `uncompress' function */
     727  
     728      stream.next_in  = (Bytef*)input;
     729      stream.avail_in = (uInt)input_len;
     730  
     731      stream.next_out  = output;
     732      stream.avail_out = (uInt)*output_len;
     733  
     734      stream.zalloc = ft_gzip_alloc;
     735      stream.zfree  = ft_gzip_free;
     736      stream.opaque = memory;
     737  
     738      err = inflateInit2( &stream, MAX_WBITS|32 );
     739  
     740      if ( err != Z_OK )
     741        return FT_THROW( Invalid_Argument );
     742  
     743      err = inflate( &stream, Z_FINISH );
     744      if ( err != Z_STREAM_END )
     745      {
     746        inflateEnd( &stream );
     747        if ( err == Z_OK )
     748          err = Z_BUF_ERROR;
     749      }
     750      else
     751      {
     752        *output_len = stream.total_out;
     753  
     754        err = inflateEnd( &stream );
     755      }
     756  
     757      if ( err == Z_MEM_ERROR )
     758        return FT_THROW( Out_Of_Memory );
     759  
     760      if ( err == Z_BUF_ERROR )
     761        return FT_THROW( Array_Too_Large );
     762  
     763      if ( err == Z_DATA_ERROR )
     764        return FT_THROW( Invalid_Table );
     765  
     766      if ( err == Z_NEED_DICT )
     767        return FT_THROW( Invalid_Table );
     768  
     769      return FT_Err_Ok;
     770    }
     771  
     772  
     773  #else /* !FT_CONFIG_OPTION_USE_ZLIB */
     774  
     775    FT_EXPORT_DEF( FT_Error )
     776    FT_Stream_OpenGzip( FT_Stream  stream,
     777                        FT_Stream  source )
     778    {
     779      FT_UNUSED( stream );
     780      FT_UNUSED( source );
     781  
     782      return FT_THROW( Unimplemented_Feature );
     783    }
     784  
     785  
     786    FT_EXPORT_DEF( FT_Error )
     787    FT_Gzip_Uncompress( FT_Memory       memory,
     788                        FT_Byte*        output,
     789                        FT_ULong*       output_len,
     790                        const FT_Byte*  input,
     791                        FT_ULong        input_len )
     792    {
     793      FT_UNUSED( memory );
     794      FT_UNUSED( output );
     795      FT_UNUSED( output_len );
     796      FT_UNUSED( input );
     797      FT_UNUSED( input_len );
     798  
     799      return FT_THROW( Unimplemented_Feature );
     800    }
     801  
     802  #endif /* !FT_CONFIG_OPTION_USE_ZLIB */
     803  
     804  
     805  /* END */