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-2017 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 ft_gzip_alloc(FT_Memory memory,uInt items,uInt size)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 ft_gzip_free(FT_Memory memory,voidpf address)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 zcalloc(voidpf opaque,unsigned items,unsigned size)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 zcfree(voidpf opaque,voidpf ptr)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 ft_gzip_check_header(FT_Stream stream)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 ft_gzip_file_init(FT_GZipFile zip,FT_Stream stream,FT_Stream source)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 ft_gzip_file_done(FT_GZipFile zip)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 ft_gzip_file_reset(FT_GZipFile zip)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 ft_gzip_file_fill_input(FT_GZipFile zip)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 ft_gzip_file_fill_output(FT_GZipFile zip)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 ft_gzip_file_skip_output(FT_GZipFile zip,FT_ULong count)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 ft_gzip_file_io(FT_GZipFile zip,FT_ULong pos,FT_Byte * buffer,FT_ULong count)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 ft_gzip_stream_close(FT_Stream stream)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 ft_gzip_stream_io(FT_Stream stream,unsigned long offset,unsigned char * buffer,unsigned long count)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 ft_gzip_get_uncompressed_size(FT_Stream stream)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 ) FT_Stream_OpenGzip(FT_Stream stream,FT_Stream source)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 ) FT_Gzip_Uncompress(FT_Memory memory,FT_Byte * output,FT_ULong * output_len,const FT_Byte * input,FT_ULong input_len)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 ) FT_Stream_OpenGzip(FT_Stream stream,FT_Stream source)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 ) FT_Gzip_Uncompress(FT_Memory memory,FT_Byte * output,FT_ULong * output_len,const FT_Byte * input,FT_ULong input_len)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 */ 817