[FREETYPE] Update to v2.9.0 and use this as a chance to slim down our lib a bit....
[reactos.git] / sdk / lib / 3rdparty / freetype / src / gzip / ftgzip.c
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-2018 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 `gzip' 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 #ifndef USE_ZLIB_ZCALLOC
62 #define MY_ZCALLOC /* prevent all zcalloc() & zfree() in zutil.c */
63 #endif
64
65 /* Note that our `zlib.h' includes `ftzconf.h' instead of `zconf.h'; */
66 /* the main reason is that even a global `zlib.h' includes `zconf.h' */
67 /* with */
68 /* */
69 /* #include "zconf.h" */
70 /* */
71 /* instead of the expected */
72 /* */
73 /* #include <zconf.h> */
74 /* */
75 /* so that configuration with `FT_CONFIG_OPTION_SYSTEM_ZLIB' might */
76 /* include the wrong `zconf.h' file, leading to errors. */
77 #include "zlib.h"
78
79 #undef SLOW
80 #define SLOW 1 /* we can't use asm-optimized sources here! */
81
82 #if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */
83 /* We disable the warning `conversion from XXX to YYY, */
84 /* possible loss of data' in order to compile cleanly with */
85 /* the maximum level of warnings: zlib is non-FreeType */
86 /* code. */
87 #pragma warning( push )
88 #pragma warning( disable : 4244 )
89 #endif /* _MSC_VER */
90
91 /* Urgh. `inflate_mask' must not be declared twice -- C++ doesn't like
92 this. We temporarily disable it and load all necessary header files. */
93 #define NO_INFLATE_MASK
94 #include "zutil.h"
95 #include "inftrees.h"
96 #include "infblock.h"
97 #include "infcodes.h"
98 #include "infutil.h"
99 #undef NO_INFLATE_MASK
100
101 /* infutil.c must be included before infcodes.c */
102 #include "zutil.c"
103 #include "inftrees.c"
104 #include "infutil.c"
105 #include "infcodes.c"
106 #include "infblock.c"
107 #include "inflate.c"
108 #include "adler32.c"
109
110 #if defined( _MSC_VER )
111 #pragma warning( pop )
112 #endif
113
114 #endif /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */
115
116
117 /***************************************************************************/
118 /***************************************************************************/
119 /***** *****/
120 /***** Z L I B M E M O R Y M A N A G E M E N T *****/
121 /***** *****/
122 /***************************************************************************/
123 /***************************************************************************/
124
125 /* it is better to use FreeType memory routines instead of raw
126 'malloc/free' */
127
128 static voidpf
129 ft_gzip_alloc( FT_Memory memory,
130 uInt items,
131 uInt size )
132 {
133 FT_ULong sz = (FT_ULong)size * items;
134 FT_Error error;
135 FT_Pointer p = NULL;
136
137
138 (void)FT_ALLOC( p, sz );
139 return p;
140 }
141
142
143 static void
144 ft_gzip_free( FT_Memory memory,
145 voidpf address )
146 {
147 FT_MEM_FREE( address );
148 }
149
150
151 #if !defined( FT_CONFIG_OPTION_SYSTEM_ZLIB ) && !defined( USE_ZLIB_ZCALLOC )
152
153 local voidpf
154 zcalloc ( voidpf opaque,
155 unsigned items,
156 unsigned size )
157 {
158 return ft_gzip_alloc( (FT_Memory)opaque, items, size );
159 }
160
161 local void
162 zcfree( voidpf opaque,
163 voidpf ptr )
164 {
165 ft_gzip_free( (FT_Memory)opaque, ptr );
166 }
167
168 #endif /* !SYSTEM_ZLIB && !USE_ZLIB_ZCALLOC */
169
170
171 /***************************************************************************/
172 /***************************************************************************/
173 /***** *****/
174 /***** Z L I B F I L E D E S C R I P T O R *****/
175 /***** *****/
176 /***************************************************************************/
177 /***************************************************************************/
178
179 #define FT_GZIP_BUFFER_SIZE 4096
180
181 typedef struct FT_GZipFileRec_
182 {
183 FT_Stream source; /* parent/source stream */
184 FT_Stream stream; /* embedding stream */
185 FT_Memory memory; /* memory allocator */
186 z_stream zstream; /* zlib input stream */
187
188 FT_ULong start; /* starting position, after .gz header */
189 FT_Byte input[FT_GZIP_BUFFER_SIZE]; /* input read buffer */
190
191 FT_Byte buffer[FT_GZIP_BUFFER_SIZE]; /* output buffer */
192 FT_ULong pos; /* position in output */
193 FT_Byte* cursor;
194 FT_Byte* limit;
195
196 } FT_GZipFileRec, *FT_GZipFile;
197
198
199 /* gzip flag byte */
200 #define FT_GZIP_ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
201 #define FT_GZIP_HEAD_CRC 0x02 /* bit 1 set: header CRC present */
202 #define FT_GZIP_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
203 #define FT_GZIP_ORIG_NAME 0x08 /* bit 3 set: original file name present */
204 #define FT_GZIP_COMMENT 0x10 /* bit 4 set: file comment present */
205 #define FT_GZIP_RESERVED 0xE0 /* bits 5..7: reserved */
206
207
208 /* check and skip .gz header - we don't support `transparent' compression */
209 static FT_Error
210 ft_gzip_check_header( FT_Stream stream )
211 {
212 FT_Error error;
213 FT_Byte head[4];
214
215
216 if ( FT_STREAM_SEEK( 0 ) ||
217 FT_STREAM_READ( head, 4 ) )
218 goto Exit;
219
220 /* head[0] && head[1] are the magic numbers; */
221 /* head[2] is the method, and head[3] the flags */
222 if ( head[0] != 0x1F ||
223 head[1] != 0x8B ||
224 head[2] != Z_DEFLATED ||
225 (head[3] & FT_GZIP_RESERVED) )
226 {
227 error = FT_THROW( Invalid_File_Format );
228 goto Exit;
229 }
230
231 /* skip time, xflags and os code */
232 (void)FT_STREAM_SKIP( 6 );
233
234 /* skip the extra field */
235 if ( head[3] & FT_GZIP_EXTRA_FIELD )
236 {
237 FT_UInt len;
238
239
240 if ( FT_READ_USHORT_LE( len ) ||
241 FT_STREAM_SKIP( len ) )
242 goto Exit;
243 }
244
245 /* skip original file name */
246 if ( head[3] & FT_GZIP_ORIG_NAME )
247 for (;;)
248 {
249 FT_UInt c;
250
251
252 if ( FT_READ_BYTE( c ) )
253 goto Exit;
254
255 if ( c == 0 )
256 break;
257 }
258
259 /* skip .gz comment */
260 if ( head[3] & FT_GZIP_COMMENT )
261 for (;;)
262 {
263 FT_UInt c;
264
265
266 if ( FT_READ_BYTE( c ) )
267 goto Exit;
268
269 if ( c == 0 )
270 break;
271 }
272
273 /* skip CRC */
274 if ( head[3] & FT_GZIP_HEAD_CRC )
275 if ( FT_STREAM_SKIP( 2 ) )
276 goto Exit;
277
278 Exit:
279 return error;
280 }
281
282
283 static FT_Error
284 ft_gzip_file_init( FT_GZipFile zip,
285 FT_Stream stream,
286 FT_Stream source )
287 {
288 z_stream* zstream = &zip->zstream;
289 FT_Error error = FT_Err_Ok;
290
291
292 zip->stream = stream;
293 zip->source = source;
294 zip->memory = stream->memory;
295
296 zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE;
297 zip->cursor = zip->limit;
298 zip->pos = 0;
299
300 /* check and skip .gz header */
301 {
302 stream = source;
303
304 error = ft_gzip_check_header( stream );
305 if ( error )
306 goto Exit;
307
308 zip->start = FT_STREAM_POS();
309 }
310
311 /* initialize zlib -- there is no zlib header in the compressed stream */
312 zstream->zalloc = (alloc_func)ft_gzip_alloc;
313 zstream->zfree = (free_func) ft_gzip_free;
314 zstream->opaque = stream->memory;
315
316 zstream->avail_in = 0;
317 zstream->next_in = zip->buffer;
318
319 if ( inflateInit2( zstream, -MAX_WBITS ) != Z_OK ||
320 !zstream->next_in )
321 error = FT_THROW( Invalid_File_Format );
322
323 Exit:
324 return error;
325 }
326
327
328 static void
329 ft_gzip_file_done( FT_GZipFile zip )
330 {
331 z_stream* zstream = &zip->zstream;
332
333
334 inflateEnd( zstream );
335
336 /* clear the rest */
337 zstream->zalloc = NULL;
338 zstream->zfree = NULL;
339 zstream->opaque = NULL;
340 zstream->next_in = NULL;
341 zstream->next_out = NULL;
342 zstream->avail_in = 0;
343 zstream->avail_out = 0;
344
345 zip->memory = NULL;
346 zip->source = NULL;
347 zip->stream = NULL;
348 }
349
350
351 static FT_Error
352 ft_gzip_file_reset( FT_GZipFile zip )
353 {
354 FT_Stream stream = zip->source;
355 FT_Error error;
356
357
358 if ( !FT_STREAM_SEEK( zip->start ) )
359 {
360 z_stream* zstream = &zip->zstream;
361
362
363 inflateReset( zstream );
364
365 zstream->avail_in = 0;
366 zstream->next_in = zip->input;
367 zstream->avail_out = 0;
368 zstream->next_out = zip->buffer;
369
370 zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE;
371 zip->cursor = zip->limit;
372 zip->pos = 0;
373 }
374
375 return error;
376 }
377
378
379 static FT_Error
380 ft_gzip_file_fill_input( FT_GZipFile zip )
381 {
382 z_stream* zstream = &zip->zstream;
383 FT_Stream stream = zip->source;
384 FT_ULong size;
385
386
387 if ( stream->read )
388 {
389 size = stream->read( stream, stream->pos, zip->input,
390 FT_GZIP_BUFFER_SIZE );
391 if ( size == 0 )
392 {
393 zip->limit = zip->cursor;
394 return FT_THROW( Invalid_Stream_Operation );
395 }
396 }
397 else
398 {
399 size = stream->size - stream->pos;
400 if ( size > FT_GZIP_BUFFER_SIZE )
401 size = FT_GZIP_BUFFER_SIZE;
402
403 if ( size == 0 )
404 {
405 zip->limit = zip->cursor;
406 return FT_THROW( Invalid_Stream_Operation );
407 }
408
409 FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
410 }
411 stream->pos += size;
412
413 zstream->next_in = zip->input;
414 zstream->avail_in = size;
415
416 return FT_Err_Ok;
417 }
418
419
420 static FT_Error
421 ft_gzip_file_fill_output( FT_GZipFile zip )
422 {
423 z_stream* zstream = &zip->zstream;
424 FT_Error error = FT_Err_Ok;
425
426
427 zip->cursor = zip->buffer;
428 zstream->next_out = zip->cursor;
429 zstream->avail_out = FT_GZIP_BUFFER_SIZE;
430
431 while ( zstream->avail_out > 0 )
432 {
433 int err;
434
435
436 if ( zstream->avail_in == 0 )
437 {
438 error = ft_gzip_file_fill_input( zip );
439 if ( error )
440 break;
441 }
442
443 err = inflate( zstream, Z_NO_FLUSH );
444
445 if ( err == Z_STREAM_END )
446 {
447 zip->limit = zstream->next_out;
448 if ( zip->limit == zip->cursor )
449 error = FT_THROW( Invalid_Stream_Operation );
450 break;
451 }
452 else if ( err != Z_OK )
453 {
454 zip->limit = zip->cursor;
455 error = FT_THROW( Invalid_Stream_Operation );
456 break;
457 }
458 }
459
460 return error;
461 }
462
463
464 /* fill output buffer; `count' must be <= FT_GZIP_BUFFER_SIZE */
465 static FT_Error
466 ft_gzip_file_skip_output( FT_GZipFile zip,
467 FT_ULong count )
468 {
469 FT_Error error = FT_Err_Ok;
470 FT_ULong delta;
471
472
473 for (;;)
474 {
475 delta = (FT_ULong)( zip->limit - zip->cursor );
476 if ( delta >= count )
477 delta = count;
478
479 zip->cursor += delta;
480 zip->pos += delta;
481
482 count -= delta;
483 if ( count == 0 )
484 break;
485
486 error = ft_gzip_file_fill_output( zip );
487 if ( error )
488 break;
489 }
490
491 return error;
492 }
493
494
495 static FT_ULong
496 ft_gzip_file_io( FT_GZipFile zip,
497 FT_ULong pos,
498 FT_Byte* buffer,
499 FT_ULong count )
500 {
501 FT_ULong result = 0;
502 FT_Error error;
503
504
505 /* Reset inflate stream if we're seeking backwards. */
506 /* Yes, that is not too efficient, but it saves memory :-) */
507 if ( pos < zip->pos )
508 {
509 error = ft_gzip_file_reset( zip );
510 if ( error )
511 goto Exit;
512 }
513
514 /* skip unwanted bytes */
515 if ( pos > zip->pos )
516 {
517 error = ft_gzip_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
518 if ( error )
519 goto Exit;
520 }
521
522 if ( count == 0 )
523 goto Exit;
524
525 /* now read the data */
526 for (;;)
527 {
528 FT_ULong delta;
529
530
531 delta = (FT_ULong)( zip->limit - zip->cursor );
532 if ( delta >= count )
533 delta = count;
534
535 FT_MEM_COPY( buffer, zip->cursor, delta );
536 buffer += delta;
537 result += delta;
538 zip->cursor += delta;
539 zip->pos += delta;
540
541 count -= delta;
542 if ( count == 0 )
543 break;
544
545 error = ft_gzip_file_fill_output( zip );
546 if ( error )
547 break;
548 }
549
550 Exit:
551 return result;
552 }
553
554
555 /***************************************************************************/
556 /***************************************************************************/
557 /***** *****/
558 /***** G Z E M B E D D I N G S T R E A M *****/
559 /***** *****/
560 /***************************************************************************/
561 /***************************************************************************/
562
563 static void
564 ft_gzip_stream_close( FT_Stream stream )
565 {
566 FT_GZipFile zip = (FT_GZipFile)stream->descriptor.pointer;
567 FT_Memory memory = stream->memory;
568
569
570 if ( zip )
571 {
572 /* finalize gzip file descriptor */
573 ft_gzip_file_done( zip );
574
575 FT_FREE( zip );
576
577 stream->descriptor.pointer = NULL;
578 }
579
580 if ( !stream->read )
581 FT_FREE( stream->base );
582 }
583
584
585 static unsigned long
586 ft_gzip_stream_io( FT_Stream stream,
587 unsigned long offset,
588 unsigned char* buffer,
589 unsigned long count )
590 {
591 FT_GZipFile zip = (FT_GZipFile)stream->descriptor.pointer;
592
593
594 return ft_gzip_file_io( zip, offset, buffer, count );
595 }
596
597
598 static FT_ULong
599 ft_gzip_get_uncompressed_size( FT_Stream stream )
600 {
601 FT_Error error;
602 FT_ULong old_pos;
603 FT_ULong result = 0;
604
605
606 old_pos = stream->pos;
607 if ( !FT_Stream_Seek( stream, stream->size - 4 ) )
608 {
609 result = FT_Stream_ReadULongLE( stream, &error );
610 if ( error )
611 result = 0;
612
613 (void)FT_Stream_Seek( stream, old_pos );
614 }
615
616 return result;
617 }
618
619
620 /* documentation is in ftgzip.h */
621
622 FT_EXPORT_DEF( FT_Error )
623 FT_Stream_OpenGzip( FT_Stream stream,
624 FT_Stream source )
625 {
626 FT_Error error;
627 FT_Memory memory;
628 FT_GZipFile zip = NULL;
629
630
631 if ( !stream || !source )
632 {
633 error = FT_THROW( Invalid_Stream_Handle );
634 goto Exit;
635 }
636
637 memory = source->memory;
638
639 /*
640 * check the header right now; this prevents allocating un-necessary
641 * objects when we don't need them
642 */
643 error = ft_gzip_check_header( source );
644 if ( error )
645 goto Exit;
646
647 FT_ZERO( stream );
648 stream->memory = memory;
649
650 if ( !FT_QNEW( zip ) )
651 {
652 error = ft_gzip_file_init( zip, stream, source );
653 if ( error )
654 {
655 FT_FREE( zip );
656 goto Exit;
657 }
658
659 stream->descriptor.pointer = zip;
660 }
661
662 /*
663 * We use the following trick to try to dramatically improve the
664 * performance while dealing with small files. If the original stream
665 * size is less than a certain threshold, we try to load the whole font
666 * file into memory. This saves us from using the 32KB buffer needed
667 * to inflate the file, plus the two 4KB intermediate input/output
668 * buffers used in the `FT_GZipFile' structure.
669 */
670 {
671 FT_ULong zip_size = ft_gzip_get_uncompressed_size( source );
672
673
674 if ( zip_size != 0 && zip_size < 40 * 1024 )
675 {
676 FT_Byte* zip_buff = NULL;
677
678
679 if ( !FT_ALLOC( zip_buff, zip_size ) )
680 {
681 FT_ULong count;
682
683
684 count = ft_gzip_file_io( zip, 0, zip_buff, zip_size );
685 if ( count == zip_size )
686 {
687 ft_gzip_file_done( zip );
688 FT_FREE( zip );
689
690 stream->descriptor.pointer = NULL;
691
692 stream->size = zip_size;
693 stream->pos = 0;
694 stream->base = zip_buff;
695 stream->read = NULL;
696 stream->close = ft_gzip_stream_close;
697
698 goto Exit;
699 }
700
701 ft_gzip_file_io( zip, 0, NULL, 0 );
702 FT_FREE( zip_buff );
703 }
704 error = FT_Err_Ok;
705 }
706
707 if ( zip_size )
708 stream->size = zip_size;
709 else
710 stream->size = 0x7FFFFFFFL; /* don't know the real size! */
711 }
712
713 stream->pos = 0;
714 stream->base = NULL;
715 stream->read = ft_gzip_stream_io;
716 stream->close = ft_gzip_stream_close;
717
718 Exit:
719 return error;
720 }
721
722
723 /* documentation is in ftgzip.h */
724
725 FT_EXPORT_DEF( FT_Error )
726 FT_Gzip_Uncompress( FT_Memory memory,
727 FT_Byte* output,
728 FT_ULong* output_len,
729 const FT_Byte* input,
730 FT_ULong input_len )
731 {
732 z_stream stream;
733 int err;
734
735
736 /* check for `input' delayed to `inflate' */
737
738 if ( !memory || ! output_len || !output )
739 return FT_THROW( Invalid_Argument );
740
741 /* this function is modeled after zlib's `uncompress' function */
742
743 stream.next_in = (Bytef*)input;
744 stream.avail_in = (uInt)input_len;
745
746 stream.next_out = output;
747 stream.avail_out = (uInt)*output_len;
748
749 stream.zalloc = (alloc_func)ft_gzip_alloc;
750 stream.zfree = (free_func) ft_gzip_free;
751 stream.opaque = memory;
752
753 err = inflateInit2( &stream, MAX_WBITS );
754 if ( err != Z_OK )
755 return FT_THROW( Invalid_Argument );
756
757 err = inflate( &stream, Z_FINISH );
758 if ( err != Z_STREAM_END )
759 {
760 inflateEnd( &stream );
761 if ( err == Z_OK )
762 err = Z_BUF_ERROR;
763 }
764 else
765 {
766 *output_len = stream.total_out;
767
768 err = inflateEnd( &stream );
769 }
770
771 if ( err == Z_MEM_ERROR )
772 return FT_THROW( Out_Of_Memory );
773
774 if ( err == Z_BUF_ERROR )
775 return FT_THROW( Array_Too_Large );
776
777 if ( err == Z_DATA_ERROR )
778 return FT_THROW( Invalid_Table );
779
780 return FT_Err_Ok;
781 }
782
783
784 #else /* !FT_CONFIG_OPTION_USE_ZLIB */
785
786 FT_EXPORT_DEF( FT_Error )
787 FT_Stream_OpenGzip( FT_Stream stream,
788 FT_Stream source )
789 {
790 FT_UNUSED( stream );
791 FT_UNUSED( source );
792
793 return FT_THROW( Unimplemented_Feature );
794 }
795
796
797 FT_EXPORT_DEF( FT_Error )
798 FT_Gzip_Uncompress( FT_Memory memory,
799 FT_Byte* output,
800 FT_ULong* output_len,
801 const FT_Byte* input,
802 FT_ULong input_len )
803 {
804 FT_UNUSED( memory );
805 FT_UNUSED( output );
806 FT_UNUSED( output_len );
807 FT_UNUSED( input );
808 FT_UNUSED( input_len );
809
810 return FT_THROW( Unimplemented_Feature );
811 }
812
813 #endif /* !FT_CONFIG_OPTION_USE_ZLIB */
814
815
816 /* END */