Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  ftbzip2.c                                                              */
  4. /*                                                                         */
  5. /*    FreeType support for .bz2 compressed files.                          */
  6. /*                                                                         */
  7. /*  This optional component relies on libbz2.  It should mainly be used to */
  8. /*  parse compressed PCF fonts, as found with many X11 server              */
  9. /*  distributions.                                                         */
  10. /*                                                                         */
  11. /*  Copyright 2010, 2012, 2013 by                                          */
  12. /*  Joel Klinghed.                                                         */
  13. /*                                                                         */
  14. /*  Based on src/gzip/ftgzip.c, Copyright 2002 - 2010 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.  
  26. #include <ft2build.h>
  27. #include FT_INTERNAL_MEMORY_H
  28. #include FT_INTERNAL_STREAM_H
  29. #include FT_INTERNAL_DEBUG_H
  30. #include FT_BZIP2_H
  31. #include FT_CONFIG_STANDARD_LIBRARY_H
  32.  
  33.  
  34. #include FT_MODULE_ERRORS_H
  35.  
  36. #undef __FTERRORS_H__
  37.  
  38. #undef  FT_ERR_PREFIX
  39. #define FT_ERR_PREFIX  Bzip2_Err_
  40. #define FT_ERR_BASE    FT_Mod_Err_Bzip2
  41.  
  42. #include FT_ERRORS_H
  43.  
  44.  
  45. #ifdef FT_CONFIG_OPTION_USE_BZIP2
  46.  
  47. #ifdef FT_CONFIG_OPTION_PIC
  48. #error "bzip2 code does not support PIC yet"
  49. #endif
  50.  
  51. #define BZ_NO_STDIO /* Do not need FILE */
  52. #include <bzlib.h>
  53.  
  54.  
  55. /***************************************************************************/
  56. /***************************************************************************/
  57. /*****                                                                 *****/
  58. /*****           B Z I P 2   M E M O R Y   M A N A G E M E N T         *****/
  59. /*****                                                                 *****/
  60. /***************************************************************************/
  61. /***************************************************************************/
  62.  
  63.   /* it is better to use FreeType memory routines instead of raw
  64.      'malloc/free' */
  65.  
  66.   typedef void *(* alloc_func)(void*, int, int);
  67.   typedef void (* free_func)(void*, void*);
  68.  
  69.   static void*
  70.   ft_bzip2_alloc( FT_Memory  memory,
  71.                   int        items,
  72.                   int        size )
  73.   {
  74.     FT_ULong    sz = (FT_ULong)size * items;
  75.     FT_Error    error;
  76.     FT_Pointer  p  = NULL;
  77.  
  78.  
  79.     (void)FT_ALLOC( p, sz );
  80.     return p;
  81.   }
  82.  
  83.  
  84.   static void
  85.   ft_bzip2_free( FT_Memory  memory,
  86.                  void*      address )
  87.   {
  88.     FT_MEM_FREE( address );
  89.   }
  90.  
  91.  
  92. /***************************************************************************/
  93. /***************************************************************************/
  94. /*****                                                                 *****/
  95. /*****              B Z I P 2   F I L E   D E S C R I P T O R          *****/
  96. /*****                                                                 *****/
  97. /***************************************************************************/
  98. /***************************************************************************/
  99.  
  100. #define FT_BZIP2_BUFFER_SIZE  4096
  101.  
  102.   typedef struct  FT_BZip2FileRec_
  103.   {
  104.     FT_Stream  source;         /* parent/source stream        */
  105.     FT_Stream  stream;         /* embedding stream            */
  106.     FT_Memory  memory;         /* memory allocator            */
  107.     bz_stream  bzstream;       /* bzlib input stream          */
  108.  
  109.     FT_Byte    input[FT_BZIP2_BUFFER_SIZE];  /* input read buffer  */
  110.  
  111.     FT_Byte    buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer      */
  112.     FT_ULong   pos;                          /* position in output */
  113.     FT_Byte*   cursor;
  114.     FT_Byte*   limit;
  115.  
  116.   } FT_BZip2FileRec, *FT_BZip2File;
  117.  
  118.  
  119.   /* check and skip .bz2 header - we don't support `transparent' compression */
  120.   static FT_Error
  121.   ft_bzip2_check_header( FT_Stream  stream )
  122.   {
  123.     FT_Error  error = FT_Err_Ok;
  124.     FT_Byte   head[4];
  125.  
  126.  
  127.     if ( FT_STREAM_SEEK( 0 )       ||
  128.          FT_STREAM_READ( head, 4 ) )
  129.       goto Exit;
  130.  
  131.     /* head[0] && head[1] are the magic numbers;    */
  132.     /* head[2] is the version, and head[3] the blocksize */
  133.     if ( head[0] != 0x42  ||
  134.          head[1] != 0x5a  ||
  135.          head[2] != 0x68  )  /* only support bzip2 (huffman) */
  136.     {
  137.       error = FT_THROW( Invalid_File_Format );
  138.       goto Exit;
  139.     }
  140.  
  141.   Exit:
  142.     return error;
  143.   }
  144.  
  145.  
  146.   static FT_Error
  147.   ft_bzip2_file_init( FT_BZip2File  zip,
  148.                       FT_Stream     stream,
  149.                       FT_Stream     source )
  150.   {
  151.     bz_stream*  bzstream = &zip->bzstream;
  152.     FT_Error    error    = FT_Err_Ok;
  153.  
  154.  
  155.     zip->stream = stream;
  156.     zip->source = source;
  157.     zip->memory = stream->memory;
  158.  
  159.     zip->limit  = zip->buffer + FT_BZIP2_BUFFER_SIZE;
  160.     zip->cursor = zip->limit;
  161.     zip->pos    = 0;
  162.  
  163.     /* check .bz2 header */
  164.     {
  165.       stream = source;
  166.  
  167.       error = ft_bzip2_check_header( stream );
  168.       if ( error )
  169.         goto Exit;
  170.  
  171.       if ( FT_STREAM_SEEK( 0 ) )
  172.         goto Exit;
  173.     }
  174.  
  175.     /* initialize bzlib */
  176.     bzstream->bzalloc = (alloc_func)ft_bzip2_alloc;
  177.     bzstream->bzfree  = (free_func) ft_bzip2_free;
  178.     bzstream->opaque  = zip->memory;
  179.  
  180.     bzstream->avail_in = 0;
  181.     bzstream->next_in  = (char*)zip->buffer;
  182.  
  183.     if ( BZ2_bzDecompressInit( bzstream, 0, 0 ) != BZ_OK ||
  184.          bzstream->next_in == NULL                       )
  185.       error = FT_THROW( Invalid_File_Format );
  186.  
  187.   Exit:
  188.     return error;
  189.   }
  190.  
  191.  
  192.   static void
  193.   ft_bzip2_file_done( FT_BZip2File  zip )
  194.   {
  195.     bz_stream*  bzstream = &zip->bzstream;
  196.  
  197.  
  198.     BZ2_bzDecompressEnd( bzstream );
  199.  
  200.     /* clear the rest */
  201.     bzstream->bzalloc   = NULL;
  202.     bzstream->bzfree    = NULL;
  203.     bzstream->opaque    = NULL;
  204.     bzstream->next_in   = NULL;
  205.     bzstream->next_out  = NULL;
  206.     bzstream->avail_in  = 0;
  207.     bzstream->avail_out = 0;
  208.  
  209.     zip->memory = NULL;
  210.     zip->source = NULL;
  211.     zip->stream = NULL;
  212.   }
  213.  
  214.  
  215.   static FT_Error
  216.   ft_bzip2_file_reset( FT_BZip2File  zip )
  217.   {
  218.     FT_Stream  stream = zip->source;
  219.     FT_Error   error;
  220.  
  221.  
  222.     if ( !FT_STREAM_SEEK( 0 ) )
  223.     {
  224.       bz_stream*  bzstream = &zip->bzstream;
  225.  
  226.  
  227.       BZ2_bzDecompressEnd( bzstream );
  228.  
  229.       bzstream->avail_in  = 0;
  230.       bzstream->next_in   = (char*)zip->input;
  231.       bzstream->avail_out = 0;
  232.       bzstream->next_out  = (char*)zip->buffer;
  233.  
  234.       zip->limit  = zip->buffer + FT_BZIP2_BUFFER_SIZE;
  235.       zip->cursor = zip->limit;
  236.       zip->pos    = 0;
  237.  
  238.       BZ2_bzDecompressInit( bzstream, 0, 0 );
  239.     }
  240.  
  241.     return error;
  242.   }
  243.  
  244.  
  245.   static FT_Error
  246.   ft_bzip2_file_fill_input( FT_BZip2File  zip )
  247.   {
  248.     bz_stream*  bzstream = &zip->bzstream;
  249.     FT_Stream   stream    = zip->source;
  250.     FT_ULong    size;
  251.  
  252.  
  253.     if ( stream->read )
  254.     {
  255.       size = stream->read( stream, stream->pos, zip->input,
  256.                            FT_BZIP2_BUFFER_SIZE );
  257.       if ( size == 0 )
  258.         return FT_THROW( Invalid_Stream_Operation );
  259.     }
  260.     else
  261.     {
  262.       size = stream->size - stream->pos;
  263.       if ( size > FT_BZIP2_BUFFER_SIZE )
  264.         size = FT_BZIP2_BUFFER_SIZE;
  265.  
  266.       if ( size == 0 )
  267.         return FT_THROW( Invalid_Stream_Operation );
  268.  
  269.       FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
  270.     }
  271.     stream->pos += size;
  272.  
  273.     bzstream->next_in  = (char*)zip->input;
  274.     bzstream->avail_in = size;
  275.  
  276.     return FT_Err_Ok;
  277.   }
  278.  
  279.  
  280.   static FT_Error
  281.   ft_bzip2_file_fill_output( FT_BZip2File  zip )
  282.   {
  283.     bz_stream*  bzstream = &zip->bzstream;
  284.     FT_Error    error    = FT_Err_Ok;
  285.  
  286.  
  287.     zip->cursor         = zip->buffer;
  288.     bzstream->next_out  = (char*)zip->cursor;
  289.     bzstream->avail_out = FT_BZIP2_BUFFER_SIZE;
  290.  
  291.     while ( bzstream->avail_out > 0 )
  292.     {
  293.       int  err;
  294.  
  295.  
  296.       if ( bzstream->avail_in == 0 )
  297.       {
  298.         error = ft_bzip2_file_fill_input( zip );
  299.         if ( error )
  300.           break;
  301.       }
  302.  
  303.       err = BZ2_bzDecompress( bzstream );
  304.  
  305.       if ( err == BZ_STREAM_END )
  306.       {
  307.         zip->limit = (FT_Byte*)bzstream->next_out;
  308.         if ( zip->limit == zip->cursor )
  309.           error = FT_THROW( Invalid_Stream_Operation );
  310.         break;
  311.       }
  312.       else if ( err != BZ_OK )
  313.       {
  314.         error = FT_THROW( Invalid_Stream_Operation );
  315.         break;
  316.       }
  317.     }
  318.  
  319.     return error;
  320.   }
  321.  
  322.  
  323.   /* fill output buffer; `count' must be <= FT_BZIP2_BUFFER_SIZE */
  324.   static FT_Error
  325.   ft_bzip2_file_skip_output( FT_BZip2File  zip,
  326.                              FT_ULong      count )
  327.   {
  328.     FT_Error  error = FT_Err_Ok;
  329.     FT_ULong  delta;
  330.  
  331.  
  332.     for (;;)
  333.     {
  334.       delta = (FT_ULong)( zip->limit - zip->cursor );
  335.       if ( delta >= count )
  336.         delta = count;
  337.  
  338.       zip->cursor += delta;
  339.       zip->pos    += delta;
  340.  
  341.       count -= delta;
  342.       if ( count == 0 )
  343.         break;
  344.  
  345.       error = ft_bzip2_file_fill_output( zip );
  346.       if ( error )
  347.         break;
  348.     }
  349.  
  350.     return error;
  351.   }
  352.  
  353.  
  354.   static FT_ULong
  355.   ft_bzip2_file_io( FT_BZip2File  zip,
  356.                     FT_ULong      pos,
  357.                     FT_Byte*      buffer,
  358.                     FT_ULong      count )
  359.   {
  360.     FT_ULong  result = 0;
  361.     FT_Error  error;
  362.  
  363.  
  364.     /* Reset inflate stream if we're seeking backwards.        */
  365.     /* Yes, that is not too efficient, but it saves memory :-) */
  366.     if ( pos < zip->pos )
  367.     {
  368.       error = ft_bzip2_file_reset( zip );
  369.       if ( error )
  370.         goto Exit;
  371.     }
  372.  
  373.     /* skip unwanted bytes */
  374.     if ( pos > zip->pos )
  375.     {
  376.       error = ft_bzip2_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
  377.       if ( error )
  378.         goto Exit;
  379.     }
  380.  
  381.     if ( count == 0 )
  382.       goto Exit;
  383.  
  384.     /* now read the data */
  385.     for (;;)
  386.     {
  387.       FT_ULong  delta;
  388.  
  389.  
  390.       delta = (FT_ULong)( zip->limit - zip->cursor );
  391.       if ( delta >= count )
  392.         delta = count;
  393.  
  394.       FT_MEM_COPY( buffer, zip->cursor, delta );
  395.       buffer      += delta;
  396.       result      += delta;
  397.       zip->cursor += delta;
  398.       zip->pos    += delta;
  399.  
  400.       count -= delta;
  401.       if ( count == 0 )
  402.         break;
  403.  
  404.       error = ft_bzip2_file_fill_output( zip );
  405.       if ( error )
  406.         break;
  407.     }
  408.  
  409.   Exit:
  410.     return result;
  411.   }
  412.  
  413.  
  414. /***************************************************************************/
  415. /***************************************************************************/
  416. /*****                                                                 *****/
  417. /*****               B Z   E M B E D D I N G   S T R E A M             *****/
  418. /*****                                                                 *****/
  419. /***************************************************************************/
  420. /***************************************************************************/
  421.  
  422.   static void
  423.   ft_bzip2_stream_close( FT_Stream  stream )
  424.   {
  425.     FT_BZip2File  zip    = (FT_BZip2File)stream->descriptor.pointer;
  426.     FT_Memory     memory = stream->memory;
  427.  
  428.  
  429.     if ( zip )
  430.     {
  431.       /* finalize bzip file descriptor */
  432.       ft_bzip2_file_done( zip );
  433.  
  434.       FT_FREE( zip );
  435.  
  436.       stream->descriptor.pointer = NULL;
  437.     }
  438.   }
  439.  
  440.  
  441.   static FT_ULong
  442.   ft_bzip2_stream_io( FT_Stream  stream,
  443.                       FT_ULong   pos,
  444.                       FT_Byte*   buffer,
  445.                       FT_ULong   count )
  446.   {
  447.     FT_BZip2File  zip = (FT_BZip2File)stream->descriptor.pointer;
  448.  
  449.  
  450.     return ft_bzip2_file_io( zip, pos, buffer, count );
  451.   }
  452.  
  453.  
  454.   FT_EXPORT_DEF( FT_Error )
  455.   FT_Stream_OpenBzip2( FT_Stream  stream,
  456.                        FT_Stream  source )
  457.   {
  458.     FT_Error      error;
  459.     FT_Memory     memory = source->memory;
  460.     FT_BZip2File  zip = NULL;
  461.  
  462.  
  463.     /*
  464.      *  check the header right now; this prevents allocating unnecessary
  465.      *  objects when we don't need them
  466.      */
  467.     error = ft_bzip2_check_header( source );
  468.     if ( error )
  469.       goto Exit;
  470.  
  471.     FT_ZERO( stream );
  472.     stream->memory = memory;
  473.  
  474.     if ( !FT_QNEW( zip ) )
  475.     {
  476.       error = ft_bzip2_file_init( zip, stream, source );
  477.       if ( error )
  478.       {
  479.         FT_FREE( zip );
  480.         goto Exit;
  481.       }
  482.  
  483.       stream->descriptor.pointer = zip;
  484.     }
  485.  
  486.     stream->size  = 0x7FFFFFFFL;  /* don't know the real size! */
  487.     stream->pos   = 0;
  488.     stream->base  = 0;
  489.     stream->read  = ft_bzip2_stream_io;
  490.     stream->close = ft_bzip2_stream_close;
  491.  
  492.   Exit:
  493.     return error;
  494.   }
  495.  
  496. #else  /* !FT_CONFIG_OPTION_USE_BZIP2 */
  497.  
  498.   FT_EXPORT_DEF( FT_Error )
  499.   FT_Stream_OpenBzip2( FT_Stream  stream,
  500.                        FT_Stream  source )
  501.   {
  502.     FT_UNUSED( stream );
  503.     FT_UNUSED( source );
  504.  
  505.     return FT_THROW( Unimplemented_Feature );
  506.   }
  507.  
  508. #endif /* !FT_CONFIG_OPTION_USE_BZIP2 */
  509.  
  510.  
  511. /* END */
  512.