tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ftgzip.c (20073B)


      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-2025 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 */