source: trunk/poppler/freetype-2.1.10/src/gzip/ftgzip.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 16 years ago

First import

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