tor-browser

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

ftlzw.c (9899B)


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