ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ftgzip.c
Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ftgzip.c                                                               */
00004 /*                                                                         */
00005 /*    FreeType support for .gz compressed files.                           */
00006 /*                                                                         */
00007 /*  This optional component relies on zlib.  It should mainly be used to   */
00008 /*  parse compressed PCF fonts, as found with many X11 server              */
00009 /*  distributions.                                                         */
00010 /*                                                                         */
00011 /*  Copyright 2002, 2003, 2004, 2005, 2006, 2009, 2010 by                  */
00012 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00013 /*                                                                         */
00014 /*  This file is part of the FreeType project, and may only be used,       */
00015 /*  modified, and distributed under the terms of the FreeType project      */
00016 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00017 /*  this file you indicate that you have read the license and              */
00018 /*  understand and accept it fully.                                        */
00019 /*                                                                         */
00020 /***************************************************************************/
00021 
00022 
00023 #include <ft2build.h>
00024 #include FT_INTERNAL_MEMORY_H
00025 #include FT_INTERNAL_STREAM_H
00026 #include FT_INTERNAL_DEBUG_H
00027 #include FT_GZIP_H
00028 #include FT_CONFIG_STANDARD_LIBRARY_H
00029 
00030 
00031 #include FT_MODULE_ERRORS_H
00032 
00033 #undef __FTERRORS_H__
00034 
00035 #define FT_ERR_PREFIX  Gzip_Err_
00036 #define FT_ERR_BASE    FT_Mod_Err_Gzip
00037 
00038 #include FT_ERRORS_H
00039 
00040 
00041 #ifdef FT_CONFIG_OPTION_USE_ZLIB
00042 
00043 #ifdef FT_CONFIG_OPTION_PIC
00044 #error "gzip code does not support PIC yet"
00045 #endif 
00046 
00047 #ifdef FT_CONFIG_OPTION_SYSTEM_ZLIB
00048 
00049 #include <zlib.h>
00050 
00051 #else /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */
00052 
00053  /* In this case, we include our own modified sources of the ZLib    */
00054  /* within the "ftgzip" component.  The modifications were necessary */
00055  /* to #include all files without conflicts, as well as preventing   */
00056  /* the definition of "extern" functions that may cause linking      */
00057  /* conflicts when a program is linked with both FreeType and the    */
00058  /* original ZLib.                                                   */
00059 
00060 #define NO_DUMMY_DECL
00061 #ifndef USE_ZLIB_ZCALLOC
00062 #define MY_ZCALLOC /* prevent all zcalloc() & zfree() in zutils.c */
00063 #endif
00064 
00065 #include "zlib.h"
00066 
00067 #undef  SLOW
00068 #define SLOW  1  /* we can't use asm-optimized sources here! */
00069 
00070   /* Urgh.  `inflate_mask' must not be declared twice -- C++ doesn't like
00071      this.  We temporarily disable it and load all necessary header files. */
00072 #define NO_INFLATE_MASK
00073 #include "zutil.h"
00074 #include "inftrees.h"
00075 #include "infblock.h"
00076 #include "infcodes.h"
00077 #include "infutil.h"
00078 #undef  NO_INFLATE_MASK
00079 
00080   /* infutil.c must be included before infcodes.c */
00081 #include "zutil.c"
00082 #include "inftrees.c"
00083 #include "infutil.c"
00084 #include "infcodes.c"
00085 #include "infblock.c"
00086 #include "inflate.c"
00087 #include "adler32.c"
00088 
00089 #endif /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */
00090 
00091 
00092 /***************************************************************************/
00093 /***************************************************************************/
00094 /*****                                                                 *****/
00095 /*****            Z L I B   M E M O R Y   M A N A G E M E N T          *****/
00096 /*****                                                                 *****/
00097 /***************************************************************************/
00098 /***************************************************************************/
00099 
00100   /* it is better to use FreeType memory routines instead of raw
00101      'malloc/free' */
00102 
00103   static voidpf
00104   ft_gzip_alloc( FT_Memory  memory,
00105                  uInt       items,
00106                  uInt       size )
00107   {
00108     FT_ULong    sz = (FT_ULong)size * items;
00109     FT_Error    error;
00110     FT_Pointer  p  = NULL;
00111 
00112 
00113     (void)FT_ALLOC( p, sz );
00114     return p;
00115   }
00116 
00117 
00118   static void
00119   ft_gzip_free( FT_Memory  memory,
00120                 voidpf     address )
00121   {
00122     FT_MEM_FREE( address );
00123   }
00124 
00125 
00126 #if !defined( FT_CONFIG_OPTION_SYSTEM_ZLIB ) && !defined( USE_ZLIB_ZCALLOC )
00127 
00128   local voidpf
00129   zcalloc ( voidpf    opaque,
00130             unsigned  items,
00131             unsigned  size )
00132   {
00133     return ft_gzip_alloc( (FT_Memory)opaque, items, size );
00134   }
00135 
00136   local void
00137   zcfree( voidpf  opaque,
00138           voidpf  ptr )
00139   {
00140     ft_gzip_free( (FT_Memory)opaque, ptr );
00141   }
00142 
00143 #endif /* !SYSTEM_ZLIB && !USE_ZLIB_ZCALLOC */
00144 
00145 
00146 /***************************************************************************/
00147 /***************************************************************************/
00148 /*****                                                                 *****/
00149 /*****               Z L I B   F I L E   D E S C R I P T O R           *****/
00150 /*****                                                                 *****/
00151 /***************************************************************************/
00152 /***************************************************************************/
00153 
00154 #define FT_GZIP_BUFFER_SIZE  4096
00155 
00156   typedef struct  FT_GZipFileRec_
00157   {
00158     FT_Stream  source;         /* parent/source stream        */
00159     FT_Stream  stream;         /* embedding stream            */
00160     FT_Memory  memory;         /* memory allocator            */
00161     z_stream   zstream;        /* zlib input stream           */
00162 
00163     FT_ULong   start;          /* starting position, after .gz header */
00164     FT_Byte    input[FT_GZIP_BUFFER_SIZE];   /* input read buffer  */
00165 
00166     FT_Byte    buffer[FT_GZIP_BUFFER_SIZE];  /* output buffer      */
00167     FT_ULong   pos;                          /* position in output */
00168     FT_Byte*   cursor;
00169     FT_Byte*   limit;
00170 
00171   } FT_GZipFileRec, *FT_GZipFile;
00172 
00173 
00174   /* gzip flag byte */
00175 #define FT_GZIP_ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
00176 #define FT_GZIP_HEAD_CRC     0x02 /* bit 1 set: header CRC present */
00177 #define FT_GZIP_EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
00178 #define FT_GZIP_ORIG_NAME    0x08 /* bit 3 set: original file name present */
00179 #define FT_GZIP_COMMENT      0x10 /* bit 4 set: file comment present */
00180 #define FT_GZIP_RESERVED     0xE0 /* bits 5..7: reserved */
00181 
00182 
00183   /* check and skip .gz header - we don't support `transparent' compression */
00184   static FT_Error
00185   ft_gzip_check_header( FT_Stream  stream )
00186   {
00187     FT_Error  error;
00188     FT_Byte   head[4];
00189 
00190 
00191     if ( FT_STREAM_SEEK( 0 )       ||
00192          FT_STREAM_READ( head, 4 ) )
00193       goto Exit;
00194 
00195     /* head[0] && head[1] are the magic numbers;    */
00196     /* head[2] is the method, and head[3] the flags */
00197     if ( head[0] != 0x1f              ||
00198          head[1] != 0x8b              ||
00199          head[2] != Z_DEFLATED        ||
00200         (head[3] & FT_GZIP_RESERVED)  )
00201     {
00202       error = Gzip_Err_Invalid_File_Format;
00203       goto Exit;
00204     }
00205 
00206     /* skip time, xflags and os code */
00207     (void)FT_STREAM_SKIP( 6 );
00208 
00209     /* skip the extra field */
00210     if ( head[3] & FT_GZIP_EXTRA_FIELD )
00211     {
00212       FT_UInt  len;
00213 
00214 
00215       if ( FT_READ_USHORT_LE( len ) ||
00216            FT_STREAM_SKIP( len )    )
00217         goto Exit;
00218     }
00219 
00220     /* skip original file name */
00221     if ( head[3] & FT_GZIP_ORIG_NAME )
00222       for (;;)
00223       {
00224         FT_UInt  c;
00225 
00226 
00227         if ( FT_READ_BYTE( c ) )
00228           goto Exit;
00229 
00230         if ( c == 0 )
00231           break;
00232       }
00233 
00234     /* skip .gz comment */
00235     if ( head[3] & FT_GZIP_COMMENT )
00236       for (;;)
00237       {
00238         FT_UInt  c;
00239 
00240 
00241         if ( FT_READ_BYTE( c ) )
00242           goto Exit;
00243 
00244         if ( c == 0 )
00245           break;
00246       }
00247 
00248     /* skip CRC */
00249     if ( head[3] & FT_GZIP_HEAD_CRC )
00250       if ( FT_STREAM_SKIP( 2 ) )
00251         goto Exit;
00252 
00253   Exit:
00254     return error;
00255   }
00256 
00257 
00258   static FT_Error
00259   ft_gzip_file_init( FT_GZipFile  zip,
00260                      FT_Stream    stream,
00261                      FT_Stream    source )
00262   {
00263     z_stream*  zstream = &zip->zstream;
00264     FT_Error   error   = Gzip_Err_Ok;
00265 
00266 
00267     zip->stream = stream;
00268     zip->source = source;
00269     zip->memory = stream->memory;
00270 
00271     zip->limit  = zip->buffer + FT_GZIP_BUFFER_SIZE;
00272     zip->cursor = zip->limit;
00273     zip->pos    = 0;
00274 
00275     /* check and skip .gz header */
00276     {
00277       stream = source;
00278 
00279       error = ft_gzip_check_header( stream );
00280       if ( error )
00281         goto Exit;
00282 
00283       zip->start = FT_STREAM_POS();
00284     }
00285 
00286     /* initialize zlib -- there is no zlib header in the compressed stream */
00287     zstream->zalloc = (alloc_func)ft_gzip_alloc;
00288     zstream->zfree  = (free_func) ft_gzip_free;
00289     zstream->opaque = stream->memory;
00290 
00291     zstream->avail_in = 0;
00292     zstream->next_in  = zip->buffer;
00293 
00294     if ( inflateInit2( zstream, -MAX_WBITS ) != Z_OK ||
00295          zstream->next_in == NULL                     )
00296       error = Gzip_Err_Invalid_File_Format;
00297 
00298   Exit:
00299     return error;
00300   }
00301 
00302 
00303   static void
00304   ft_gzip_file_done( FT_GZipFile  zip )
00305   {
00306     z_stream*  zstream = &zip->zstream;
00307 
00308 
00309     inflateEnd( zstream );
00310 
00311     /* clear the rest */
00312     zstream->zalloc    = NULL;
00313     zstream->zfree     = NULL;
00314     zstream->opaque    = NULL;
00315     zstream->next_in   = NULL;
00316     zstream->next_out  = NULL;
00317     zstream->avail_in  = 0;
00318     zstream->avail_out = 0;
00319 
00320     zip->memory = NULL;
00321     zip->source = NULL;
00322     zip->stream = NULL;
00323   }
00324 
00325 
00326   static FT_Error
00327   ft_gzip_file_reset( FT_GZipFile  zip )
00328   {
00329     FT_Stream  stream = zip->source;
00330     FT_Error   error;
00331 
00332 
00333     if ( !FT_STREAM_SEEK( zip->start ) )
00334     {
00335       z_stream*  zstream = &zip->zstream;
00336 
00337 
00338       inflateReset( zstream );
00339 
00340       zstream->avail_in  = 0;
00341       zstream->next_in   = zip->input;
00342       zstream->avail_out = 0;
00343       zstream->next_out  = zip->buffer;
00344 
00345       zip->limit  = zip->buffer + FT_GZIP_BUFFER_SIZE;
00346       zip->cursor = zip->limit;
00347       zip->pos    = 0;
00348     }
00349 
00350     return error;
00351   }
00352 
00353 
00354   static FT_Error
00355   ft_gzip_file_fill_input( FT_GZipFile  zip )
00356   {
00357     z_stream*  zstream = &zip->zstream;
00358     FT_Stream  stream  = zip->source;
00359     FT_ULong   size;
00360 
00361 
00362     if ( stream->read )
00363     {
00364       size = stream->read( stream, stream->pos, zip->input,
00365                            FT_GZIP_BUFFER_SIZE );
00366       if ( size == 0 )
00367         return Gzip_Err_Invalid_Stream_Operation;
00368     }
00369     else
00370     {
00371       size = stream->size - stream->pos;
00372       if ( size > FT_GZIP_BUFFER_SIZE )
00373         size = FT_GZIP_BUFFER_SIZE;
00374 
00375       if ( size == 0 )
00376         return Gzip_Err_Invalid_Stream_Operation;
00377 
00378       FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
00379     }
00380     stream->pos += size;
00381 
00382     zstream->next_in  = zip->input;
00383     zstream->avail_in = size;
00384 
00385     return Gzip_Err_Ok;
00386   }
00387 
00388 
00389   static FT_Error
00390   ft_gzip_file_fill_output( FT_GZipFile  zip )
00391   {
00392     z_stream*  zstream = &zip->zstream;
00393     FT_Error   error   = Gzip_Err_Ok;
00394 
00395 
00396     zip->cursor        = zip->buffer;
00397     zstream->next_out  = zip->cursor;
00398     zstream->avail_out = FT_GZIP_BUFFER_SIZE;
00399 
00400     while ( zstream->avail_out > 0 )
00401     {
00402       int  err;
00403 
00404 
00405       if ( zstream->avail_in == 0 )
00406       {
00407         error = ft_gzip_file_fill_input( zip );
00408         if ( error )
00409           break;
00410       }
00411 
00412       err = inflate( zstream, Z_NO_FLUSH );
00413 
00414       if ( err == Z_STREAM_END )
00415       {
00416         zip->limit = zstream->next_out;
00417         if ( zip->limit == zip->cursor )
00418           error = Gzip_Err_Invalid_Stream_Operation;
00419         break;
00420       }
00421       else if ( err != Z_OK )
00422       {
00423         error = Gzip_Err_Invalid_Stream_Operation;
00424         break;
00425       }
00426     }
00427 
00428     return error;
00429   }
00430 
00431 
00432   /* fill output buffer; `count' must be <= FT_GZIP_BUFFER_SIZE */
00433   static FT_Error
00434   ft_gzip_file_skip_output( FT_GZipFile  zip,
00435                             FT_ULong     count )
00436   {
00437     FT_Error  error = Gzip_Err_Ok;
00438     FT_ULong  delta;
00439 
00440 
00441     for (;;)
00442     {
00443       delta = (FT_ULong)( zip->limit - zip->cursor );
00444       if ( delta >= count )
00445         delta = count;
00446 
00447       zip->cursor += delta;
00448       zip->pos    += delta;
00449 
00450       count -= delta;
00451       if ( count == 0 )
00452         break;
00453 
00454       error = ft_gzip_file_fill_output( zip );
00455       if ( error )
00456         break;
00457     }
00458 
00459     return error;
00460   }
00461 
00462 
00463   static FT_ULong
00464   ft_gzip_file_io( FT_GZipFile  zip,
00465                    FT_ULong     pos,
00466                    FT_Byte*     buffer,
00467                    FT_ULong     count )
00468   {
00469     FT_ULong  result = 0;
00470     FT_Error  error;
00471 
00472 
00473     /* Reset inflate stream if we're seeking backwards.        */
00474     /* Yes, that is not too efficient, but it saves memory :-) */
00475     if ( pos < zip->pos )
00476     {
00477       error = ft_gzip_file_reset( zip );
00478       if ( error )
00479         goto Exit;
00480     }
00481 
00482     /* skip unwanted bytes */
00483     if ( pos > zip->pos )
00484     {
00485       error = ft_gzip_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
00486       if ( error )
00487         goto Exit;
00488     }
00489 
00490     if ( count == 0 )
00491       goto Exit;
00492 
00493     /* now read the data */
00494     for (;;)
00495     {
00496       FT_ULong  delta;
00497 
00498 
00499       delta = (FT_ULong)( zip->limit - zip->cursor );
00500       if ( delta >= count )
00501         delta = count;
00502 
00503       FT_MEM_COPY( buffer, zip->cursor, delta );
00504       buffer      += delta;
00505       result      += delta;
00506       zip->cursor += delta;
00507       zip->pos    += delta;
00508 
00509       count -= delta;
00510       if ( count == 0 )
00511         break;
00512 
00513       error = ft_gzip_file_fill_output( zip );
00514       if ( error )
00515         break;
00516     }
00517 
00518   Exit:
00519     return result;
00520   }
00521 
00522 
00523 /***************************************************************************/
00524 /***************************************************************************/
00525 /*****                                                                 *****/
00526 /*****               G Z   E M B E D D I N G   S T R E A M             *****/
00527 /*****                                                                 *****/
00528 /***************************************************************************/
00529 /***************************************************************************/
00530 
00531   static void
00532   ft_gzip_stream_close( FT_Stream  stream )
00533   {
00534     FT_GZipFile  zip    = (FT_GZipFile)stream->descriptor.pointer;
00535     FT_Memory    memory = stream->memory;
00536 
00537 
00538     if ( zip )
00539     {
00540       /* finalize gzip file descriptor */
00541       ft_gzip_file_done( zip );
00542 
00543       FT_FREE( zip );
00544 
00545       stream->descriptor.pointer = NULL;
00546     }
00547   }
00548 
00549 
00550   static FT_ULong
00551   ft_gzip_stream_io( FT_Stream  stream,
00552                      FT_ULong   pos,
00553                      FT_Byte*   buffer,
00554                      FT_ULong   count )
00555   {
00556     FT_GZipFile  zip = (FT_GZipFile)stream->descriptor.pointer;
00557 
00558 
00559     return ft_gzip_file_io( zip, pos, buffer, count );
00560   }
00561 
00562 
00563   static FT_ULong
00564   ft_gzip_get_uncompressed_size( FT_Stream  stream )
00565   {
00566     FT_Error  error;
00567     FT_ULong  old_pos;
00568     FT_ULong  result = 0;
00569 
00570 
00571     old_pos = stream->pos;
00572     if ( !FT_Stream_Seek( stream, stream->size - 4 ) )
00573     {
00574       result = (FT_ULong)FT_Stream_ReadLong( stream, &error );
00575       if ( error )
00576         result = 0;
00577 
00578       (void)FT_Stream_Seek( stream, old_pos );
00579     }
00580 
00581     return result;
00582   }
00583 
00584 
00585   FT_EXPORT_DEF( FT_Error )
00586   FT_Stream_OpenGzip( FT_Stream  stream,
00587                       FT_Stream  source )
00588   {
00589     FT_Error     error;
00590     FT_Memory    memory = source->memory;
00591     FT_GZipFile  zip;
00592 
00593 
00594     /*
00595      *  check the header right now; this prevents allocating un-necessary
00596      *  objects when we don't need them
00597      */
00598     error = ft_gzip_check_header( source );
00599     if ( error )
00600       goto Exit;
00601 
00602     FT_ZERO( stream );
00603     stream->memory = memory;
00604 
00605     if ( !FT_QNEW( zip ) )
00606     {
00607       error = ft_gzip_file_init( zip, stream, source );
00608       if ( error )
00609       {
00610         FT_FREE( zip );
00611         goto Exit;
00612       }
00613 
00614       stream->descriptor.pointer = zip;
00615     }
00616 
00617     /*
00618      *  We use the following trick to try to dramatically improve the
00619      *  performance while dealing with small files.  If the original stream
00620      *  size is less than a certain threshold, we try to load the whole font
00621      *  file into memory.  This saves us from using the 32KB buffer needed
00622      *  to inflate the file, plus the two 4KB intermediate input/output
00623      *  buffers used in the `FT_GZipFile' structure.
00624      */
00625     {
00626       FT_ULong  zip_size = ft_gzip_get_uncompressed_size( source );
00627 
00628 
00629       if ( zip_size != 0 && zip_size < 40 * 1024 )
00630       {
00631         FT_Byte*  zip_buff;
00632 
00633 
00634         if ( !FT_ALLOC( zip_buff, zip_size ) )
00635         {
00636           FT_ULong  count;
00637 
00638 
00639           count = ft_gzip_file_io( zip, 0, zip_buff, zip_size );
00640           if ( count == zip_size )
00641           {
00642             ft_gzip_file_done( zip );
00643             FT_FREE( zip );
00644 
00645             stream->descriptor.pointer = NULL;
00646 
00647             stream->size  = zip_size;
00648             stream->pos   = 0;
00649             stream->base  = zip_buff;
00650             stream->read  = NULL;
00651             stream->close = ft_gzip_stream_close;
00652 
00653             goto Exit;
00654           }
00655 
00656           ft_gzip_file_io( zip, 0, NULL, 0 );
00657           FT_FREE( zip_buff );
00658         }
00659         error = Gzip_Err_Ok;
00660       }
00661     }
00662 
00663     stream->size  = 0x7FFFFFFFL;  /* don't know the real size! */
00664     stream->pos   = 0;
00665     stream->base  = 0;
00666     stream->read  = ft_gzip_stream_io;
00667     stream->close = ft_gzip_stream_close;
00668 
00669   Exit:
00670     return error;
00671   }
00672 
00673 #else  /* !FT_CONFIG_OPTION_USE_ZLIB */
00674 
00675   FT_EXPORT_DEF( FT_Error )
00676   FT_Stream_OpenGzip( FT_Stream  stream,
00677                       FT_Stream  source )
00678   {
00679     FT_UNUSED( stream );
00680     FT_UNUSED( source );
00681 
00682     return Gzip_Err_Unimplemented_Feature;
00683   }
00684 
00685 #endif /* !FT_CONFIG_OPTION_USE_ZLIB */
00686 
00687 
00688 /* END */

Generated on Sun May 27 2012 04:33:51 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.