Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

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