misc/libfreetype/src/gzip/ftgzip.c
changeset 5172 88f2e05288ba
equal deleted inserted replaced
5171:f9283dc4860d 5172:88f2e05288ba
       
     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 2002-2006, 2009-2011 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 <ft2build.h>
       
    24 #include FT_INTERNAL_MEMORY_H
       
    25 #include FT_INTERNAL_STREAM_H
       
    26 #include FT_INTERNAL_DEBUG_H
       
    27 #include FT_GZIP_H
       
    28 #include FT_CONFIG_STANDARD_LIBRARY_H
       
    29 
       
    30 
       
    31 #include FT_MODULE_ERRORS_H
       
    32 
       
    33 #undef __FTERRORS_H__
       
    34 
       
    35 #define FT_ERR_PREFIX  Gzip_Err_
       
    36 #define FT_ERR_BASE    FT_Mod_Err_Gzip
       
    37 
       
    38 #include FT_ERRORS_H
       
    39 
       
    40 
       
    41 #ifdef FT_CONFIG_OPTION_USE_ZLIB
       
    42 
       
    43 #ifdef FT_CONFIG_OPTION_PIC
       
    44 #error "gzip code does not support PIC yet"
       
    45 #endif 
       
    46 
       
    47 #ifdef FT_CONFIG_OPTION_SYSTEM_ZLIB
       
    48 
       
    49 #include <zlib.h>
       
    50 
       
    51 #else /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */
       
    52 
       
    53  /* In this case, we include our own modified sources of the ZLib    */
       
    54  /* within the "ftgzip" component.  The modifications were necessary */
       
    55  /* to #include all files without conflicts, as well as preventing   */
       
    56  /* the definition of "extern" functions that may cause linking      */
       
    57  /* conflicts when a program is linked with both FreeType and the    */
       
    58  /* original ZLib.                                                   */
       
    59 
       
    60 #define NO_DUMMY_DECL
       
    61 #ifndef USE_ZLIB_ZCALLOC
       
    62 #define MY_ZCALLOC /* prevent all zcalloc() & zfree() in zutils.c */
       
    63 #endif
       
    64 
       
    65 #include "zlib.h"
       
    66 
       
    67 #undef  SLOW
       
    68 #define SLOW  1  /* we can't use asm-optimized sources here! */
       
    69 
       
    70   /* Urgh.  `inflate_mask' must not be declared twice -- C++ doesn't like
       
    71      this.  We temporarily disable it and load all necessary header files. */
       
    72 #define NO_INFLATE_MASK
       
    73 #include "zutil.h"
       
    74 #include "inftrees.h"
       
    75 #include "infblock.h"
       
    76 #include "infcodes.h"
       
    77 #include "infutil.h"
       
    78 #undef  NO_INFLATE_MASK
       
    79 
       
    80   /* infutil.c must be included before infcodes.c */
       
    81 #include "zutil.c"
       
    82 #include "inftrees.c"
       
    83 #include "infutil.c"
       
    84 #include "infcodes.c"
       
    85 #include "infblock.c"
       
    86 #include "inflate.c"
       
    87 #include "adler32.c"
       
    88 
       
    89 #endif /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */
       
    90 
       
    91 
       
    92 /***************************************************************************/
       
    93 /***************************************************************************/
       
    94 /*****                                                                 *****/
       
    95 /*****            Z L I B   M E M O R Y   M A N A G E M E N T          *****/
       
    96 /*****                                                                 *****/
       
    97 /***************************************************************************/
       
    98 /***************************************************************************/
       
    99 
       
   100   /* it is better to use FreeType memory routines instead of raw
       
   101      'malloc/free' */
       
   102 
       
   103   static voidpf
       
   104   ft_gzip_alloc( FT_Memory  memory,
       
   105                  uInt       items,
       
   106                  uInt       size )
       
   107   {
       
   108     FT_ULong    sz = (FT_ULong)size * items;
       
   109     FT_Error    error;
       
   110     FT_Pointer  p  = NULL;
       
   111 
       
   112 
       
   113     (void)FT_ALLOC( p, sz );
       
   114     return p;
       
   115   }
       
   116 
       
   117 
       
   118   static void
       
   119   ft_gzip_free( FT_Memory  memory,
       
   120                 voidpf     address )
       
   121   {
       
   122     FT_MEM_FREE( address );
       
   123   }
       
   124 
       
   125 
       
   126 #if !defined( FT_CONFIG_OPTION_SYSTEM_ZLIB ) && !defined( USE_ZLIB_ZCALLOC )
       
   127 
       
   128   local voidpf
       
   129   zcalloc ( voidpf    opaque,
       
   130             unsigned  items,
       
   131             unsigned  size )
       
   132   {
       
   133     return ft_gzip_alloc( (FT_Memory)opaque, items, size );
       
   134   }
       
   135 
       
   136   local void
       
   137   zcfree( voidpf  opaque,
       
   138           voidpf  ptr )
       
   139   {
       
   140     ft_gzip_free( (FT_Memory)opaque, ptr );
       
   141   }
       
   142 
       
   143 #endif /* !SYSTEM_ZLIB && !USE_ZLIB_ZCALLOC */
       
   144 
       
   145 
       
   146 /***************************************************************************/
       
   147 /***************************************************************************/
       
   148 /*****                                                                 *****/
       
   149 /*****               Z L I B   F I L E   D E S C R I P T O R           *****/
       
   150 /*****                                                                 *****/
       
   151 /***************************************************************************/
       
   152 /***************************************************************************/
       
   153 
       
   154 #define FT_GZIP_BUFFER_SIZE  4096
       
   155 
       
   156   typedef struct  FT_GZipFileRec_
       
   157   {
       
   158     FT_Stream  source;         /* parent/source stream        */
       
   159     FT_Stream  stream;         /* embedding stream            */
       
   160     FT_Memory  memory;         /* memory allocator            */
       
   161     z_stream   zstream;        /* zlib input stream           */
       
   162 
       
   163     FT_ULong   start;          /* starting position, after .gz header */
       
   164     FT_Byte    input[FT_GZIP_BUFFER_SIZE];   /* input read buffer  */
       
   165 
       
   166     FT_Byte    buffer[FT_GZIP_BUFFER_SIZE];  /* output buffer      */
       
   167     FT_ULong   pos;                          /* position in output */
       
   168     FT_Byte*   cursor;
       
   169     FT_Byte*   limit;
       
   170 
       
   171   } FT_GZipFileRec, *FT_GZipFile;
       
   172 
       
   173 
       
   174   /* gzip flag byte */
       
   175 #define FT_GZIP_ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
       
   176 #define FT_GZIP_HEAD_CRC     0x02 /* bit 1 set: header CRC present */
       
   177 #define FT_GZIP_EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
       
   178 #define FT_GZIP_ORIG_NAME    0x08 /* bit 3 set: original file name present */
       
   179 #define FT_GZIP_COMMENT      0x10 /* bit 4 set: file comment present */
       
   180 #define FT_GZIP_RESERVED     0xE0 /* bits 5..7: reserved */
       
   181 
       
   182 
       
   183   /* check and skip .gz header - we don't support `transparent' compression */
       
   184   static FT_Error
       
   185   ft_gzip_check_header( FT_Stream  stream )
       
   186   {
       
   187     FT_Error  error;
       
   188     FT_Byte   head[4];
       
   189 
       
   190 
       
   191     if ( FT_STREAM_SEEK( 0 )       ||
       
   192          FT_STREAM_READ( head, 4 ) )
       
   193       goto Exit;
       
   194 
       
   195     /* head[0] && head[1] are the magic numbers;    */
       
   196     /* head[2] is the method, and head[3] the flags */
       
   197     if ( head[0] != 0x1f              ||
       
   198          head[1] != 0x8b              ||
       
   199          head[2] != Z_DEFLATED        ||
       
   200         (head[3] & FT_GZIP_RESERVED)  )
       
   201     {
       
   202       error = Gzip_Err_Invalid_File_Format;
       
   203       goto Exit;
       
   204     }
       
   205 
       
   206     /* skip time, xflags and os code */
       
   207     (void)FT_STREAM_SKIP( 6 );
       
   208 
       
   209     /* skip the extra field */
       
   210     if ( head[3] & FT_GZIP_EXTRA_FIELD )
       
   211     {
       
   212       FT_UInt  len;
       
   213 
       
   214 
       
   215       if ( FT_READ_USHORT_LE( len ) ||
       
   216            FT_STREAM_SKIP( len )    )
       
   217         goto Exit;
       
   218     }
       
   219 
       
   220     /* skip original file name */
       
   221     if ( head[3] & FT_GZIP_ORIG_NAME )
       
   222       for (;;)
       
   223       {
       
   224         FT_UInt  c;
       
   225 
       
   226 
       
   227         if ( FT_READ_BYTE( c ) )
       
   228           goto Exit;
       
   229 
       
   230         if ( c == 0 )
       
   231           break;
       
   232       }
       
   233 
       
   234     /* skip .gz comment */
       
   235     if ( head[3] & FT_GZIP_COMMENT )
       
   236       for (;;)
       
   237       {
       
   238         FT_UInt  c;
       
   239 
       
   240 
       
   241         if ( FT_READ_BYTE( c ) )
       
   242           goto Exit;
       
   243 
       
   244         if ( c == 0 )
       
   245           break;
       
   246       }
       
   247 
       
   248     /* skip CRC */
       
   249     if ( head[3] & FT_GZIP_HEAD_CRC )
       
   250       if ( FT_STREAM_SKIP( 2 ) )
       
   251         goto Exit;
       
   252 
       
   253   Exit:
       
   254     return error;
       
   255   }
       
   256 
       
   257 
       
   258   static FT_Error
       
   259   ft_gzip_file_init( FT_GZipFile  zip,
       
   260                      FT_Stream    stream,
       
   261                      FT_Stream    source )
       
   262   {
       
   263     z_stream*  zstream = &zip->zstream;
       
   264     FT_Error   error   = Gzip_Err_Ok;
       
   265 
       
   266 
       
   267     zip->stream = stream;
       
   268     zip->source = source;
       
   269     zip->memory = stream->memory;
       
   270 
       
   271     zip->limit  = zip->buffer + FT_GZIP_BUFFER_SIZE;
       
   272     zip->cursor = zip->limit;
       
   273     zip->pos    = 0;
       
   274 
       
   275     /* check and skip .gz header */
       
   276     {
       
   277       stream = source;
       
   278 
       
   279       error = ft_gzip_check_header( stream );
       
   280       if ( error )
       
   281         goto Exit;
       
   282 
       
   283       zip->start = FT_STREAM_POS();
       
   284     }
       
   285 
       
   286     /* initialize zlib -- there is no zlib header in the compressed stream */
       
   287     zstream->zalloc = (alloc_func)ft_gzip_alloc;
       
   288     zstream->zfree  = (free_func) ft_gzip_free;
       
   289     zstream->opaque = stream->memory;
       
   290 
       
   291     zstream->avail_in = 0;
       
   292     zstream->next_in  = zip->buffer;
       
   293 
       
   294     if ( inflateInit2( zstream, -MAX_WBITS ) != Z_OK ||
       
   295          zstream->next_in == NULL                     )
       
   296       error = Gzip_Err_Invalid_File_Format;
       
   297 
       
   298   Exit:
       
   299     return error;
       
   300   }
       
   301 
       
   302 
       
   303   static void
       
   304   ft_gzip_file_done( FT_GZipFile  zip )
       
   305   {
       
   306     z_stream*  zstream = &zip->zstream;
       
   307 
       
   308 
       
   309     inflateEnd( zstream );
       
   310 
       
   311     /* clear the rest */
       
   312     zstream->zalloc    = NULL;
       
   313     zstream->zfree     = NULL;
       
   314     zstream->opaque    = NULL;
       
   315     zstream->next_in   = NULL;
       
   316     zstream->next_out  = NULL;
       
   317     zstream->avail_in  = 0;
       
   318     zstream->avail_out = 0;
       
   319 
       
   320     zip->memory = NULL;
       
   321     zip->source = NULL;
       
   322     zip->stream = NULL;
       
   323   }
       
   324 
       
   325 
       
   326   static FT_Error
       
   327   ft_gzip_file_reset( FT_GZipFile  zip )
       
   328   {
       
   329     FT_Stream  stream = zip->source;
       
   330     FT_Error   error;
       
   331 
       
   332 
       
   333     if ( !FT_STREAM_SEEK( zip->start ) )
       
   334     {
       
   335       z_stream*  zstream = &zip->zstream;
       
   336 
       
   337 
       
   338       inflateReset( zstream );
       
   339 
       
   340       zstream->avail_in  = 0;
       
   341       zstream->next_in   = zip->input;
       
   342       zstream->avail_out = 0;
       
   343       zstream->next_out  = zip->buffer;
       
   344 
       
   345       zip->limit  = zip->buffer + FT_GZIP_BUFFER_SIZE;
       
   346       zip->cursor = zip->limit;
       
   347       zip->pos    = 0;
       
   348     }
       
   349 
       
   350     return error;
       
   351   }
       
   352 
       
   353 
       
   354   static FT_Error
       
   355   ft_gzip_file_fill_input( FT_GZipFile  zip )
       
   356   {
       
   357     z_stream*  zstream = &zip->zstream;
       
   358     FT_Stream  stream  = zip->source;
       
   359     FT_ULong   size;
       
   360 
       
   361 
       
   362     if ( stream->read )
       
   363     {
       
   364       size = stream->read( stream, stream->pos, zip->input,
       
   365                            FT_GZIP_BUFFER_SIZE );
       
   366       if ( size == 0 )
       
   367         return Gzip_Err_Invalid_Stream_Operation;
       
   368     }
       
   369     else
       
   370     {
       
   371       size = stream->size - stream->pos;
       
   372       if ( size > FT_GZIP_BUFFER_SIZE )
       
   373         size = FT_GZIP_BUFFER_SIZE;
       
   374 
       
   375       if ( size == 0 )
       
   376         return Gzip_Err_Invalid_Stream_Operation;
       
   377 
       
   378       FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
       
   379     }
       
   380     stream->pos += size;
       
   381 
       
   382     zstream->next_in  = zip->input;
       
   383     zstream->avail_in = size;
       
   384 
       
   385     return Gzip_Err_Ok;
       
   386   }
       
   387 
       
   388 
       
   389   static FT_Error
       
   390   ft_gzip_file_fill_output( FT_GZipFile  zip )
       
   391   {
       
   392     z_stream*  zstream = &zip->zstream;
       
   393     FT_Error   error   = Gzip_Err_Ok;
       
   394 
       
   395 
       
   396     zip->cursor        = zip->buffer;
       
   397     zstream->next_out  = zip->cursor;
       
   398     zstream->avail_out = FT_GZIP_BUFFER_SIZE;
       
   399 
       
   400     while ( zstream->avail_out > 0 )
       
   401     {
       
   402       int  err;
       
   403 
       
   404 
       
   405       if ( zstream->avail_in == 0 )
       
   406       {
       
   407         error = ft_gzip_file_fill_input( zip );
       
   408         if ( error )
       
   409           break;
       
   410       }
       
   411 
       
   412       err = inflate( zstream, Z_NO_FLUSH );
       
   413 
       
   414       if ( err == Z_STREAM_END )
       
   415       {
       
   416         zip->limit = zstream->next_out;
       
   417         if ( zip->limit == zip->cursor )
       
   418           error = Gzip_Err_Invalid_Stream_Operation;
       
   419         break;
       
   420       }
       
   421       else if ( err != Z_OK )
       
   422       {
       
   423         error = Gzip_Err_Invalid_Stream_Operation;
       
   424         break;
       
   425       }
       
   426     }
       
   427 
       
   428     return error;
       
   429   }
       
   430 
       
   431 
       
   432   /* fill output buffer; `count' must be <= FT_GZIP_BUFFER_SIZE */
       
   433   static FT_Error
       
   434   ft_gzip_file_skip_output( FT_GZipFile  zip,
       
   435                             FT_ULong     count )
       
   436   {
       
   437     FT_Error  error = Gzip_Err_Ok;
       
   438     FT_ULong  delta;
       
   439 
       
   440 
       
   441     for (;;)
       
   442     {
       
   443       delta = (FT_ULong)( zip->limit - zip->cursor );
       
   444       if ( delta >= count )
       
   445         delta = count;
       
   446 
       
   447       zip->cursor += delta;
       
   448       zip->pos    += delta;
       
   449 
       
   450       count -= delta;
       
   451       if ( count == 0 )
       
   452         break;
       
   453 
       
   454       error = ft_gzip_file_fill_output( zip );
       
   455       if ( error )
       
   456         break;
       
   457     }
       
   458 
       
   459     return error;
       
   460   }
       
   461 
       
   462 
       
   463   static FT_ULong
       
   464   ft_gzip_file_io( FT_GZipFile  zip,
       
   465                    FT_ULong     pos,
       
   466                    FT_Byte*     buffer,
       
   467                    FT_ULong     count )
       
   468   {
       
   469     FT_ULong  result = 0;
       
   470     FT_Error  error;
       
   471 
       
   472 
       
   473     /* Reset inflate stream if we're seeking backwards.        */
       
   474     /* Yes, that is not too efficient, but it saves memory :-) */
       
   475     if ( pos < zip->pos )
       
   476     {
       
   477       error = ft_gzip_file_reset( zip );
       
   478       if ( error )
       
   479         goto Exit;
       
   480     }
       
   481 
       
   482     /* skip unwanted bytes */
       
   483     if ( pos > zip->pos )
       
   484     {
       
   485       error = ft_gzip_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
       
   486       if ( error )
       
   487         goto Exit;
       
   488     }
       
   489 
       
   490     if ( count == 0 )
       
   491       goto Exit;
       
   492 
       
   493     /* now read the data */
       
   494     for (;;)
       
   495     {
       
   496       FT_ULong  delta;
       
   497 
       
   498 
       
   499       delta = (FT_ULong)( zip->limit - zip->cursor );
       
   500       if ( delta >= count )
       
   501         delta = count;
       
   502 
       
   503       FT_MEM_COPY( buffer, zip->cursor, delta );
       
   504       buffer      += delta;
       
   505       result      += delta;
       
   506       zip->cursor += delta;
       
   507       zip->pos    += delta;
       
   508 
       
   509       count -= delta;
       
   510       if ( count == 0 )
       
   511         break;
       
   512 
       
   513       error = ft_gzip_file_fill_output( zip );
       
   514       if ( error )
       
   515         break;
       
   516     }
       
   517 
       
   518   Exit:
       
   519     return result;
       
   520   }
       
   521 
       
   522 
       
   523 /***************************************************************************/
       
   524 /***************************************************************************/
       
   525 /*****                                                                 *****/
       
   526 /*****               G Z   E M B E D D I N G   S T R E A M             *****/
       
   527 /*****                                                                 *****/
       
   528 /***************************************************************************/
       
   529 /***************************************************************************/
       
   530 
       
   531   static void
       
   532   ft_gzip_stream_close( FT_Stream  stream )
       
   533   {
       
   534     FT_GZipFile  zip    = (FT_GZipFile)stream->descriptor.pointer;
       
   535     FT_Memory    memory = stream->memory;
       
   536 
       
   537 
       
   538     if ( zip )
       
   539     {
       
   540       /* finalize gzip file descriptor */
       
   541       ft_gzip_file_done( zip );
       
   542 
       
   543       FT_FREE( zip );
       
   544 
       
   545       stream->descriptor.pointer = NULL;
       
   546     }
       
   547   }
       
   548 
       
   549 
       
   550   static FT_ULong
       
   551   ft_gzip_stream_io( FT_Stream  stream,
       
   552                      FT_ULong   pos,
       
   553                      FT_Byte*   buffer,
       
   554                      FT_ULong   count )
       
   555   {
       
   556     FT_GZipFile  zip = (FT_GZipFile)stream->descriptor.pointer;
       
   557 
       
   558 
       
   559     return ft_gzip_file_io( zip, pos, buffer, count );
       
   560   }
       
   561 
       
   562 
       
   563   static FT_ULong
       
   564   ft_gzip_get_uncompressed_size( FT_Stream  stream )
       
   565   {
       
   566     FT_Error  error;
       
   567     FT_ULong  old_pos;
       
   568     FT_ULong  result = 0;
       
   569 
       
   570 
       
   571     old_pos = stream->pos;
       
   572     if ( !FT_Stream_Seek( stream, stream->size - 4 ) )
       
   573     {
       
   574       result = FT_Stream_ReadULong( stream, &error );
       
   575       if ( error )
       
   576         result = 0;
       
   577 
       
   578       (void)FT_Stream_Seek( stream, old_pos );
       
   579     }
       
   580 
       
   581     return result;
       
   582   }
       
   583 
       
   584 
       
   585   FT_EXPORT_DEF( FT_Error )
       
   586   FT_Stream_OpenGzip( FT_Stream  stream,
       
   587                       FT_Stream  source )
       
   588   {
       
   589     FT_Error     error;
       
   590     FT_Memory    memory = source->memory;
       
   591     FT_GZipFile  zip;
       
   592 
       
   593 
       
   594     /*
       
   595      *  check the header right now; this prevents allocating un-necessary
       
   596      *  objects when we don't need them
       
   597      */
       
   598     error = ft_gzip_check_header( source );
       
   599     if ( error )
       
   600       goto Exit;
       
   601 
       
   602     FT_ZERO( stream );
       
   603     stream->memory = memory;
       
   604 
       
   605     if ( !FT_QNEW( zip ) )
       
   606     {
       
   607       error = ft_gzip_file_init( zip, stream, source );
       
   608       if ( error )
       
   609       {
       
   610         FT_FREE( zip );
       
   611         goto Exit;
       
   612       }
       
   613 
       
   614       stream->descriptor.pointer = zip;
       
   615     }
       
   616 
       
   617     /*
       
   618      *  We use the following trick to try to dramatically improve the
       
   619      *  performance while dealing with small files.  If the original stream
       
   620      *  size is less than a certain threshold, we try to load the whole font
       
   621      *  file into memory.  This saves us from using the 32KB buffer needed
       
   622      *  to inflate the file, plus the two 4KB intermediate input/output
       
   623      *  buffers used in the `FT_GZipFile' structure.
       
   624      */
       
   625     {
       
   626       FT_ULong  zip_size = ft_gzip_get_uncompressed_size( source );
       
   627 
       
   628 
       
   629       if ( zip_size != 0 && zip_size < 40 * 1024 )
       
   630       {
       
   631         FT_Byte*  zip_buff;
       
   632 
       
   633 
       
   634         if ( !FT_ALLOC( zip_buff, zip_size ) )
       
   635         {
       
   636           FT_ULong  count;
       
   637 
       
   638 
       
   639           count = ft_gzip_file_io( zip, 0, zip_buff, zip_size );
       
   640           if ( count == zip_size )
       
   641           {
       
   642             ft_gzip_file_done( zip );
       
   643             FT_FREE( zip );
       
   644 
       
   645             stream->descriptor.pointer = NULL;
       
   646 
       
   647             stream->size  = zip_size;
       
   648             stream->pos   = 0;
       
   649             stream->base  = zip_buff;
       
   650             stream->read  = NULL;
       
   651             stream->close = ft_gzip_stream_close;
       
   652 
       
   653             goto Exit;
       
   654           }
       
   655 
       
   656           ft_gzip_file_io( zip, 0, NULL, 0 );
       
   657           FT_FREE( zip_buff );
       
   658         }
       
   659         error = Gzip_Err_Ok;
       
   660       }
       
   661     }
       
   662 
       
   663     stream->size  = 0x7FFFFFFFL;  /* don't know the real size! */
       
   664     stream->pos   = 0;
       
   665     stream->base  = 0;
       
   666     stream->read  = ft_gzip_stream_io;
       
   667     stream->close = ft_gzip_stream_close;
       
   668 
       
   669   Exit:
       
   670     return error;
       
   671   }
       
   672 
       
   673 #else  /* !FT_CONFIG_OPTION_USE_ZLIB */
       
   674 
       
   675   FT_EXPORT_DEF( FT_Error )
       
   676   FT_Stream_OpenGzip( FT_Stream  stream,
       
   677                       FT_Stream  source )
       
   678   {
       
   679     FT_UNUSED( stream );
       
   680     FT_UNUSED( source );
       
   681 
       
   682     return Gzip_Err_Unimplemented_Feature;
       
   683   }
       
   684 
       
   685 #endif /* !FT_CONFIG_OPTION_USE_ZLIB */
       
   686 
       
   687 
       
   688 /* END */