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