misc/libfreetype/src/lzw/ftlzw.c
changeset 9431 0f5961910e27
parent 9357 a501f5ec7b34
parent 9429 7a97a554ac80
child 9433 f0a8ac191839
equal deleted inserted replaced
9357:a501f5ec7b34 9431:0f5961910e27
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  ftlzw.c                                                                */
       
     4 /*                                                                         */
       
     5 /*    FreeType support for .Z compressed files.                            */
       
     6 /*                                                                         */
       
     7 /*  This optional component relies on NetBSD's zopen().  It should mainly  */
       
     8 /*  be used to parse compressed PCF fonts, as found with many X11 server   */
       
     9 /*  distributions.                                                         */
       
    10 /*                                                                         */
       
    11 /*  Copyright 2004, 2005, 2006, 2009, 2010 by                              */
       
    12 /*  Albert Chin-A-Young.                                                   */
       
    13 /*                                                                         */
       
    14 /*  Based on code in src/gzip/ftgzip.c, Copyright 2004 by                  */
       
    15 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
       
    16 /*                                                                         */
       
    17 /*  This file is part of the FreeType project, and may only be used,       */
       
    18 /*  modified, and distributed under the terms of the FreeType project      */
       
    19 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
       
    20 /*  this file you indicate that you have read the license and              */
       
    21 /*  understand and accept it fully.                                        */
       
    22 /*                                                                         */
       
    23 /***************************************************************************/
       
    24 
       
    25 #include <ft2build.h>
       
    26 #include FT_INTERNAL_MEMORY_H
       
    27 #include FT_INTERNAL_STREAM_H
       
    28 #include FT_INTERNAL_DEBUG_H
       
    29 #include FT_LZW_H
       
    30 #include FT_CONFIG_STANDARD_LIBRARY_H
       
    31 
       
    32 
       
    33 #include FT_MODULE_ERRORS_H
       
    34 
       
    35 #undef __FTERRORS_H__
       
    36 
       
    37 #define FT_ERR_PREFIX  LZW_Err_
       
    38 #define FT_ERR_BASE    FT_Mod_Err_LZW
       
    39 
       
    40 #include FT_ERRORS_H
       
    41 
       
    42 
       
    43 #ifdef FT_CONFIG_OPTION_USE_LZW
       
    44 
       
    45 #ifdef FT_CONFIG_OPTION_PIC
       
    46 #error "lzw code does not support PIC yet"
       
    47 #endif 
       
    48 
       
    49 #include "ftzopen.h"
       
    50 
       
    51 
       
    52 /***************************************************************************/
       
    53 /***************************************************************************/
       
    54 /*****                                                                 *****/
       
    55 /*****                  M E M O R Y   M A N A G E M E N T              *****/
       
    56 /*****                                                                 *****/
       
    57 /***************************************************************************/
       
    58 /***************************************************************************/
       
    59 
       
    60 /***************************************************************************/
       
    61 /***************************************************************************/
       
    62 /*****                                                                 *****/
       
    63 /*****                   F I L E   D E S C R I P T O R                 *****/
       
    64 /*****                                                                 *****/
       
    65 /***************************************************************************/
       
    66 /***************************************************************************/
       
    67 
       
    68 #define FT_LZW_BUFFER_SIZE  4096
       
    69 
       
    70   typedef struct  FT_LZWFileRec_
       
    71   {
       
    72     FT_Stream       source;         /* parent/source stream        */
       
    73     FT_Stream       stream;         /* embedding stream            */
       
    74     FT_Memory       memory;         /* memory allocator            */
       
    75     FT_LzwStateRec  lzw;            /* lzw decompressor state      */
       
    76 
       
    77     FT_Byte         buffer[FT_LZW_BUFFER_SIZE]; /* output buffer      */
       
    78     FT_ULong        pos;                        /* position in output */
       
    79     FT_Byte*        cursor;
       
    80     FT_Byte*        limit;
       
    81 
       
    82   } FT_LZWFileRec, *FT_LZWFile;
       
    83 
       
    84 
       
    85   /* check and skip .Z header */
       
    86   static FT_Error
       
    87   ft_lzw_check_header( FT_Stream  stream )
       
    88   {
       
    89     FT_Error  error;
       
    90     FT_Byte   head[2];
       
    91 
       
    92 
       
    93     if ( FT_STREAM_SEEK( 0 )       ||
       
    94          FT_STREAM_READ( head, 2 ) )
       
    95       goto Exit;
       
    96 
       
    97     /* head[0] && head[1] are the magic numbers */
       
    98     if ( head[0] != 0x1f ||
       
    99          head[1] != 0x9d )
       
   100       error = LZW_Err_Invalid_File_Format;
       
   101 
       
   102   Exit:
       
   103     return error;
       
   104   }
       
   105 
       
   106 
       
   107   static FT_Error
       
   108   ft_lzw_file_init( FT_LZWFile  zip,
       
   109                     FT_Stream   stream,
       
   110                     FT_Stream   source )
       
   111   {
       
   112     FT_LzwState  lzw   = &zip->lzw;
       
   113     FT_Error     error = LZW_Err_Ok;
       
   114 
       
   115 
       
   116     zip->stream = stream;
       
   117     zip->source = source;
       
   118     zip->memory = stream->memory;
       
   119 
       
   120     zip->limit  = zip->buffer + FT_LZW_BUFFER_SIZE;
       
   121     zip->cursor = zip->limit;
       
   122     zip->pos    = 0;
       
   123 
       
   124     /* check and skip .Z header */
       
   125     error = ft_lzw_check_header( source );
       
   126     if ( error )
       
   127       goto Exit;
       
   128 
       
   129     /* initialize internal lzw variable */
       
   130     ft_lzwstate_init( lzw, source );
       
   131 
       
   132   Exit:
       
   133     return error;
       
   134   }
       
   135 
       
   136 
       
   137   static void
       
   138   ft_lzw_file_done( FT_LZWFile  zip )
       
   139   {
       
   140     /* clear the rest */
       
   141     ft_lzwstate_done( &zip->lzw );
       
   142 
       
   143     zip->memory = NULL;
       
   144     zip->source = NULL;
       
   145     zip->stream = NULL;
       
   146   }
       
   147 
       
   148 
       
   149   static FT_Error
       
   150   ft_lzw_file_reset( FT_LZWFile  zip )
       
   151   {
       
   152     FT_Stream  stream = zip->source;
       
   153     FT_Error   error;
       
   154 
       
   155 
       
   156     if ( !FT_STREAM_SEEK( 0 ) )
       
   157     {
       
   158       ft_lzwstate_reset( &zip->lzw );
       
   159 
       
   160       zip->limit  = zip->buffer + FT_LZW_BUFFER_SIZE;
       
   161       zip->cursor = zip->limit;
       
   162       zip->pos    = 0;
       
   163     }
       
   164 
       
   165     return error;
       
   166   }
       
   167 
       
   168 
       
   169   static FT_Error
       
   170   ft_lzw_file_fill_output( FT_LZWFile  zip )
       
   171   {
       
   172     FT_LzwState  lzw = &zip->lzw;
       
   173     FT_ULong     count;
       
   174     FT_Error     error = LZW_Err_Ok;
       
   175 
       
   176 
       
   177     zip->cursor = zip->buffer;
       
   178 
       
   179     count = ft_lzwstate_io( lzw, zip->buffer, FT_LZW_BUFFER_SIZE );
       
   180 
       
   181     zip->limit = zip->cursor + count;
       
   182 
       
   183     if ( count == 0 )
       
   184       error = LZW_Err_Invalid_Stream_Operation;
       
   185 
       
   186     return error;
       
   187   }
       
   188 
       
   189 
       
   190   /* fill output buffer; `count' must be <= FT_LZW_BUFFER_SIZE */
       
   191   static FT_Error
       
   192   ft_lzw_file_skip_output( FT_LZWFile  zip,
       
   193                            FT_ULong    count )
       
   194   {
       
   195     FT_Error  error = LZW_Err_Ok;
       
   196 
       
   197 
       
   198     /* first, we skip what we can from the output buffer */
       
   199     {
       
   200       FT_ULong  delta = (FT_ULong)( zip->limit - zip->cursor );
       
   201 
       
   202 
       
   203       if ( delta >= count )
       
   204         delta = count;
       
   205 
       
   206       zip->cursor += delta;
       
   207       zip->pos    += delta;
       
   208 
       
   209       count -= delta;
       
   210     }
       
   211 
       
   212     /* next, we skip as many bytes remaining as possible */
       
   213     while ( count > 0 )
       
   214     {
       
   215       FT_ULong  delta = FT_LZW_BUFFER_SIZE;
       
   216       FT_ULong  numread;
       
   217 
       
   218 
       
   219       if ( delta > count )
       
   220         delta = count;
       
   221 
       
   222       numread = ft_lzwstate_io( &zip->lzw, NULL, delta );
       
   223       if ( numread < delta )
       
   224       {
       
   225         /* not enough bytes */
       
   226         error = LZW_Err_Invalid_Stream_Operation;
       
   227         break;
       
   228       }
       
   229 
       
   230       zip->pos += delta;
       
   231       count    -= delta;
       
   232     }
       
   233 
       
   234     return error;
       
   235   }
       
   236 
       
   237 
       
   238   static FT_ULong
       
   239   ft_lzw_file_io( FT_LZWFile  zip,
       
   240                   FT_ULong    pos,
       
   241                   FT_Byte*    buffer,
       
   242                   FT_ULong    count )
       
   243   {
       
   244     FT_ULong  result = 0;
       
   245     FT_Error  error;
       
   246 
       
   247 
       
   248     /* seeking backwards. */
       
   249     if ( pos < zip->pos )
       
   250     {
       
   251       /* If the new position is within the output buffer, simply       */
       
   252       /* decrement pointers, otherwise we reset the stream completely! */
       
   253       if ( ( zip->pos - pos ) <= (FT_ULong)( zip->cursor - zip->buffer ) )
       
   254       {
       
   255         zip->cursor -= zip->pos - pos;
       
   256         zip->pos     = pos;
       
   257       }
       
   258       else
       
   259       {
       
   260         error = ft_lzw_file_reset( zip );
       
   261         if ( error )
       
   262           goto Exit;
       
   263       }
       
   264     }
       
   265 
       
   266     /* skip unwanted bytes */
       
   267     if ( pos > zip->pos )
       
   268     {
       
   269       error = ft_lzw_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
       
   270       if ( error )
       
   271         goto Exit;
       
   272     }
       
   273 
       
   274     if ( count == 0 )
       
   275       goto Exit;
       
   276 
       
   277     /* now read the data */
       
   278     for (;;)
       
   279     {
       
   280       FT_ULong  delta;
       
   281 
       
   282 
       
   283       delta = (FT_ULong)( zip->limit - zip->cursor );
       
   284       if ( delta >= count )
       
   285         delta = count;
       
   286 
       
   287       FT_MEM_COPY( buffer + result, zip->cursor, delta );
       
   288       result      += delta;
       
   289       zip->cursor += delta;
       
   290       zip->pos    += delta;
       
   291 
       
   292       count -= delta;
       
   293       if ( count == 0 )
       
   294         break;
       
   295 
       
   296       error = ft_lzw_file_fill_output( zip );
       
   297       if ( error )
       
   298         break;
       
   299     }
       
   300 
       
   301   Exit:
       
   302     return result;
       
   303   }
       
   304 
       
   305 
       
   306 /***************************************************************************/
       
   307 /***************************************************************************/
       
   308 /*****                                                                 *****/
       
   309 /*****            L Z W   E M B E D D I N G   S T R E A M              *****/
       
   310 /*****                                                                 *****/
       
   311 /***************************************************************************/
       
   312 /***************************************************************************/
       
   313 
       
   314   static void
       
   315   ft_lzw_stream_close( FT_Stream  stream )
       
   316   {
       
   317     FT_LZWFile  zip    = (FT_LZWFile)stream->descriptor.pointer;
       
   318     FT_Memory   memory = stream->memory;
       
   319 
       
   320 
       
   321     if ( zip )
       
   322     {
       
   323       /* finalize lzw file descriptor */
       
   324       ft_lzw_file_done( zip );
       
   325 
       
   326       FT_FREE( zip );
       
   327 
       
   328       stream->descriptor.pointer = NULL;
       
   329     }
       
   330   }
       
   331 
       
   332 
       
   333   static FT_ULong
       
   334   ft_lzw_stream_io( FT_Stream  stream,
       
   335                     FT_ULong   pos,
       
   336                     FT_Byte*   buffer,
       
   337                     FT_ULong   count )
       
   338   {
       
   339     FT_LZWFile  zip = (FT_LZWFile)stream->descriptor.pointer;
       
   340 
       
   341 
       
   342     return ft_lzw_file_io( zip, pos, buffer, count );
       
   343   }
       
   344 
       
   345 
       
   346   FT_EXPORT_DEF( FT_Error )
       
   347   FT_Stream_OpenLZW( FT_Stream  stream,
       
   348                      FT_Stream  source )
       
   349   {
       
   350     FT_Error    error;
       
   351     FT_Memory   memory = source->memory;
       
   352     FT_LZWFile  zip;
       
   353 
       
   354 
       
   355     /*
       
   356      *  Check the header right now; this prevents allocation of a huge
       
   357      *  LZWFile object (400 KByte of heap memory) if not necessary.
       
   358      *
       
   359      *  Did I mention that you should never use .Z compressed font
       
   360      *  files?
       
   361      */
       
   362     error = ft_lzw_check_header( source );
       
   363     if ( error )
       
   364       goto Exit;
       
   365 
       
   366     FT_ZERO( stream );
       
   367     stream->memory = memory;
       
   368 
       
   369     if ( !FT_NEW( zip ) )
       
   370     {
       
   371       error = ft_lzw_file_init( zip, stream, source );
       
   372       if ( error )
       
   373       {
       
   374         FT_FREE( zip );
       
   375         goto Exit;
       
   376       }
       
   377 
       
   378       stream->descriptor.pointer = zip;
       
   379     }
       
   380 
       
   381     stream->size  = 0x7FFFFFFFL;  /* don't know the real size! */
       
   382     stream->pos   = 0;
       
   383     stream->base  = 0;
       
   384     stream->read  = ft_lzw_stream_io;
       
   385     stream->close = ft_lzw_stream_close;
       
   386 
       
   387   Exit:
       
   388     return error;
       
   389   }
       
   390 
       
   391 
       
   392 #include "ftzopen.c"
       
   393 
       
   394 
       
   395 #else  /* !FT_CONFIG_OPTION_USE_LZW */
       
   396 
       
   397 
       
   398   FT_EXPORT_DEF( FT_Error )
       
   399   FT_Stream_OpenLZW( FT_Stream  stream,
       
   400                      FT_Stream  source )
       
   401   {
       
   402     FT_UNUSED( stream );
       
   403     FT_UNUSED( source );
       
   404 
       
   405     return LZW_Err_Unimplemented_Feature;
       
   406   }
       
   407 
       
   408 
       
   409 #endif /* !FT_CONFIG_OPTION_USE_LZW */
       
   410 
       
   411 
       
   412 /* END */