Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenftgzip.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* ftgzip.c */ 00004 /* */ 00005 /* FreeType support for .gz compressed files. */ 00006 /* */ 00007 /* This optional component relies on zlib. It should mainly be used to */ 00008 /* parse compressed PCF fonts, as found with many X11 server */ 00009 /* distributions. */ 00010 /* */ 00011 /* Copyright 2002, 2003, 2004, 2005, 2006, 2009, 2010 by */ 00012 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 00013 /* */ 00014 /* This file is part of the FreeType project, and may only be used, */ 00015 /* modified, and distributed under the terms of the FreeType project */ 00016 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00017 /* this file you indicate that you have read the license and */ 00018 /* understand and accept it fully. */ 00019 /* */ 00020 /***************************************************************************/ 00021 00022 00023 #include <ft2build.h> 00024 #include FT_INTERNAL_MEMORY_H 00025 #include FT_INTERNAL_STREAM_H 00026 #include FT_INTERNAL_DEBUG_H 00027 #include FT_GZIP_H 00028 #include FT_CONFIG_STANDARD_LIBRARY_H 00029 00030 00031 #include FT_MODULE_ERRORS_H 00032 00033 #undef __FTERRORS_H__ 00034 00035 #define FT_ERR_PREFIX Gzip_Err_ 00036 #define FT_ERR_BASE FT_Mod_Err_Gzip 00037 00038 #include FT_ERRORS_H 00039 00040 00041 #ifdef FT_CONFIG_OPTION_USE_ZLIB 00042 00043 #ifdef FT_CONFIG_OPTION_PIC 00044 #error "gzip code does not support PIC yet" 00045 #endif 00046 00047 #ifdef FT_CONFIG_OPTION_SYSTEM_ZLIB 00048 00049 #include <zlib.h> 00050 00051 #else /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */ 00052 00053 /* In this case, we include our own modified sources of the ZLib */ 00054 /* within the "ftgzip" component. The modifications were necessary */ 00055 /* to #include all files without conflicts, as well as preventing */ 00056 /* the definition of "extern" functions that may cause linking */ 00057 /* conflicts when a program is linked with both FreeType and the */ 00058 /* original ZLib. */ 00059 00060 #define NO_DUMMY_DECL 00061 #ifndef USE_ZLIB_ZCALLOC 00062 #define MY_ZCALLOC /* prevent all zcalloc() & zfree() in zutils.c */ 00063 #endif 00064 00065 #include "zlib.h" 00066 00067 #undef SLOW 00068 #define SLOW 1 /* we can't use asm-optimized sources here! */ 00069 00070 /* Urgh. `inflate_mask' must not be declared twice -- C++ doesn't like 00071 this. We temporarily disable it and load all necessary header files. */ 00072 #define NO_INFLATE_MASK 00073 #include "zutil.h" 00074 #include "inftrees.h" 00075 #include "infblock.h" 00076 #include "infcodes.h" 00077 #include "infutil.h" 00078 #undef NO_INFLATE_MASK 00079 00080 /* infutil.c must be included before infcodes.c */ 00081 #include "zutil.c" 00082 #include "inftrees.c" 00083 #include "infutil.c" 00084 #include "infcodes.c" 00085 #include "infblock.c" 00086 #include "inflate.c" 00087 #include "adler32.c" 00088 00089 #endif /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */ 00090 00091 00092 /***************************************************************************/ 00093 /***************************************************************************/ 00094 /***** *****/ 00095 /***** Z L I B M E M O R Y M A N A G E M E N T *****/ 00096 /***** *****/ 00097 /***************************************************************************/ 00098 /***************************************************************************/ 00099 00100 /* it is better to use FreeType memory routines instead of raw 00101 'malloc/free' */ 00102 00103 static voidpf 00104 ft_gzip_alloc( FT_Memory memory, 00105 uInt items, 00106 uInt size ) 00107 { 00108 FT_ULong sz = (FT_ULong)size * items; 00109 FT_Error error; 00110 FT_Pointer p = NULL; 00111 00112 00113 (void)FT_ALLOC( p, sz ); 00114 return p; 00115 } 00116 00117 00118 static void 00119 ft_gzip_free( FT_Memory memory, 00120 voidpf address ) 00121 { 00122 FT_MEM_FREE( address ); 00123 } 00124 00125 00126 #if !defined( FT_CONFIG_OPTION_SYSTEM_ZLIB ) && !defined( USE_ZLIB_ZCALLOC ) 00127 00128 local voidpf 00129 zcalloc ( voidpf opaque, 00130 unsigned items, 00131 unsigned size ) 00132 { 00133 return ft_gzip_alloc( (FT_Memory)opaque, items, size ); 00134 } 00135 00136 local void 00137 zcfree( voidpf opaque, 00138 voidpf ptr ) 00139 { 00140 ft_gzip_free( (FT_Memory)opaque, ptr ); 00141 } 00142 00143 #endif /* !SYSTEM_ZLIB && !USE_ZLIB_ZCALLOC */ 00144 00145 00146 /***************************************************************************/ 00147 /***************************************************************************/ 00148 /***** *****/ 00149 /***** Z L I B F I L E D E S C R I P T O R *****/ 00150 /***** *****/ 00151 /***************************************************************************/ 00152 /***************************************************************************/ 00153 00154 #define FT_GZIP_BUFFER_SIZE 4096 00155 00156 typedef struct FT_GZipFileRec_ 00157 { 00158 FT_Stream source; /* parent/source stream */ 00159 FT_Stream stream; /* embedding stream */ 00160 FT_Memory memory; /* memory allocator */ 00161 z_stream zstream; /* zlib input stream */ 00162 00163 FT_ULong start; /* starting position, after .gz header */ 00164 FT_Byte input[FT_GZIP_BUFFER_SIZE]; /* input read buffer */ 00165 00166 FT_Byte buffer[FT_GZIP_BUFFER_SIZE]; /* output buffer */ 00167 FT_ULong pos; /* position in output */ 00168 FT_Byte* cursor; 00169 FT_Byte* limit; 00170 00171 } FT_GZipFileRec, *FT_GZipFile; 00172 00173 00174 /* gzip flag byte */ 00175 #define FT_GZIP_ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ 00176 #define FT_GZIP_HEAD_CRC 0x02 /* bit 1 set: header CRC present */ 00177 #define FT_GZIP_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ 00178 #define FT_GZIP_ORIG_NAME 0x08 /* bit 3 set: original file name present */ 00179 #define FT_GZIP_COMMENT 0x10 /* bit 4 set: file comment present */ 00180 #define FT_GZIP_RESERVED 0xE0 /* bits 5..7: reserved */ 00181 00182 00183 /* check and skip .gz header - we don't support `transparent' compression */ 00184 static FT_Error 00185 ft_gzip_check_header( FT_Stream stream ) 00186 { 00187 FT_Error error; 00188 FT_Byte head[4]; 00189 00190 00191 if ( FT_STREAM_SEEK( 0 ) || 00192 FT_STREAM_READ( head, 4 ) ) 00193 goto Exit; 00194 00195 /* head[0] && head[1] are the magic numbers; */ 00196 /* head[2] is the method, and head[3] the flags */ 00197 if ( head[0] != 0x1f || 00198 head[1] != 0x8b || 00199 head[2] != Z_DEFLATED || 00200 (head[3] & FT_GZIP_RESERVED) ) 00201 { 00202 error = Gzip_Err_Invalid_File_Format; 00203 goto Exit; 00204 } 00205 00206 /* skip time, xflags and os code */ 00207 (void)FT_STREAM_SKIP( 6 ); 00208 00209 /* skip the extra field */ 00210 if ( head[3] & FT_GZIP_EXTRA_FIELD ) 00211 { 00212 FT_UInt len; 00213 00214 00215 if ( FT_READ_USHORT_LE( len ) || 00216 FT_STREAM_SKIP( len ) ) 00217 goto Exit; 00218 } 00219 00220 /* skip original file name */ 00221 if ( head[3] & FT_GZIP_ORIG_NAME ) 00222 for (;;) 00223 { 00224 FT_UInt c; 00225 00226 00227 if ( FT_READ_BYTE( c ) ) 00228 goto Exit; 00229 00230 if ( c == 0 ) 00231 break; 00232 } 00233 00234 /* skip .gz comment */ 00235 if ( head[3] & FT_GZIP_COMMENT ) 00236 for (;;) 00237 { 00238 FT_UInt c; 00239 00240 00241 if ( FT_READ_BYTE( c ) ) 00242 goto Exit; 00243 00244 if ( c == 0 ) 00245 break; 00246 } 00247 00248 /* skip CRC */ 00249 if ( head[3] & FT_GZIP_HEAD_CRC ) 00250 if ( FT_STREAM_SKIP( 2 ) ) 00251 goto Exit; 00252 00253 Exit: 00254 return error; 00255 } 00256 00257 00258 static FT_Error 00259 ft_gzip_file_init( FT_GZipFile zip, 00260 FT_Stream stream, 00261 FT_Stream source ) 00262 { 00263 z_stream* zstream = &zip->zstream; 00264 FT_Error error = Gzip_Err_Ok; 00265 00266 00267 zip->stream = stream; 00268 zip->source = source; 00269 zip->memory = stream->memory; 00270 00271 zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE; 00272 zip->cursor = zip->limit; 00273 zip->pos = 0; 00274 00275 /* check and skip .gz header */ 00276 { 00277 stream = source; 00278 00279 error = ft_gzip_check_header( stream ); 00280 if ( error ) 00281 goto Exit; 00282 00283 zip->start = FT_STREAM_POS(); 00284 } 00285 00286 /* initialize zlib -- there is no zlib header in the compressed stream */ 00287 zstream->zalloc = (alloc_func)ft_gzip_alloc; 00288 zstream->zfree = (free_func) ft_gzip_free; 00289 zstream->opaque = stream->memory; 00290 00291 zstream->avail_in = 0; 00292 zstream->next_in = zip->buffer; 00293 00294 if ( inflateInit2( zstream, -MAX_WBITS ) != Z_OK || 00295 zstream->next_in == NULL ) 00296 error = Gzip_Err_Invalid_File_Format; 00297 00298 Exit: 00299 return error; 00300 } 00301 00302 00303 static void 00304 ft_gzip_file_done( FT_GZipFile zip ) 00305 { 00306 z_stream* zstream = &zip->zstream; 00307 00308 00309 inflateEnd( zstream ); 00310 00311 /* clear the rest */ 00312 zstream->zalloc = NULL; 00313 zstream->zfree = NULL; 00314 zstream->opaque = NULL; 00315 zstream->next_in = NULL; 00316 zstream->next_out = NULL; 00317 zstream->avail_in = 0; 00318 zstream->avail_out = 0; 00319 00320 zip->memory = NULL; 00321 zip->source = NULL; 00322 zip->stream = NULL; 00323 } 00324 00325 00326 static FT_Error 00327 ft_gzip_file_reset( FT_GZipFile zip ) 00328 { 00329 FT_Stream stream = zip->source; 00330 FT_Error error; 00331 00332 00333 if ( !FT_STREAM_SEEK( zip->start ) ) 00334 { 00335 z_stream* zstream = &zip->zstream; 00336 00337 00338 inflateReset( zstream ); 00339 00340 zstream->avail_in = 0; 00341 zstream->next_in = zip->input; 00342 zstream->avail_out = 0; 00343 zstream->next_out = zip->buffer; 00344 00345 zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE; 00346 zip->cursor = zip->limit; 00347 zip->pos = 0; 00348 } 00349 00350 return error; 00351 } 00352 00353 00354 static FT_Error 00355 ft_gzip_file_fill_input( FT_GZipFile zip ) 00356 { 00357 z_stream* zstream = &zip->zstream; 00358 FT_Stream stream = zip->source; 00359 FT_ULong size; 00360 00361 00362 if ( stream->read ) 00363 { 00364 size = stream->read( stream, stream->pos, zip->input, 00365 FT_GZIP_BUFFER_SIZE ); 00366 if ( size == 0 ) 00367 return Gzip_Err_Invalid_Stream_Operation; 00368 } 00369 else 00370 { 00371 size = stream->size - stream->pos; 00372 if ( size > FT_GZIP_BUFFER_SIZE ) 00373 size = FT_GZIP_BUFFER_SIZE; 00374 00375 if ( size == 0 ) 00376 return Gzip_Err_Invalid_Stream_Operation; 00377 00378 FT_MEM_COPY( zip->input, stream->base + stream->pos, size ); 00379 } 00380 stream->pos += size; 00381 00382 zstream->next_in = zip->input; 00383 zstream->avail_in = size; 00384 00385 return Gzip_Err_Ok; 00386 } 00387 00388 00389 static FT_Error 00390 ft_gzip_file_fill_output( FT_GZipFile zip ) 00391 { 00392 z_stream* zstream = &zip->zstream; 00393 FT_Error error = Gzip_Err_Ok; 00394 00395 00396 zip->cursor = zip->buffer; 00397 zstream->next_out = zip->cursor; 00398 zstream->avail_out = FT_GZIP_BUFFER_SIZE; 00399 00400 while ( zstream->avail_out > 0 ) 00401 { 00402 int err; 00403 00404 00405 if ( zstream->avail_in == 0 ) 00406 { 00407 error = ft_gzip_file_fill_input( zip ); 00408 if ( error ) 00409 break; 00410 } 00411 00412 err = inflate( zstream, Z_NO_FLUSH ); 00413 00414 if ( err == Z_STREAM_END ) 00415 { 00416 zip->limit = zstream->next_out; 00417 if ( zip->limit == zip->cursor ) 00418 error = Gzip_Err_Invalid_Stream_Operation; 00419 break; 00420 } 00421 else if ( err != Z_OK ) 00422 { 00423 error = Gzip_Err_Invalid_Stream_Operation; 00424 break; 00425 } 00426 } 00427 00428 return error; 00429 } 00430 00431 00432 /* fill output buffer; `count' must be <= FT_GZIP_BUFFER_SIZE */ 00433 static FT_Error 00434 ft_gzip_file_skip_output( FT_GZipFile zip, 00435 FT_ULong count ) 00436 { 00437 FT_Error error = Gzip_Err_Ok; 00438 FT_ULong delta; 00439 00440 00441 for (;;) 00442 { 00443 delta = (FT_ULong)( zip->limit - zip->cursor ); 00444 if ( delta >= count ) 00445 delta = count; 00446 00447 zip->cursor += delta; 00448 zip->pos += delta; 00449 00450 count -= delta; 00451 if ( count == 0 ) 00452 break; 00453 00454 error = ft_gzip_file_fill_output( zip ); 00455 if ( error ) 00456 break; 00457 } 00458 00459 return error; 00460 } 00461 00462 00463 static FT_ULong 00464 ft_gzip_file_io( FT_GZipFile zip, 00465 FT_ULong pos, 00466 FT_Byte* buffer, 00467 FT_ULong count ) 00468 { 00469 FT_ULong result = 0; 00470 FT_Error error; 00471 00472 00473 /* Reset inflate stream if we're seeking backwards. */ 00474 /* Yes, that is not too efficient, but it saves memory :-) */ 00475 if ( pos < zip->pos ) 00476 { 00477 error = ft_gzip_file_reset( zip ); 00478 if ( error ) 00479 goto Exit; 00480 } 00481 00482 /* skip unwanted bytes */ 00483 if ( pos > zip->pos ) 00484 { 00485 error = ft_gzip_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) ); 00486 if ( error ) 00487 goto Exit; 00488 } 00489 00490 if ( count == 0 ) 00491 goto Exit; 00492 00493 /* now read the data */ 00494 for (;;) 00495 { 00496 FT_ULong delta; 00497 00498 00499 delta = (FT_ULong)( zip->limit - zip->cursor ); 00500 if ( delta >= count ) 00501 delta = count; 00502 00503 FT_MEM_COPY( buffer, zip->cursor, delta ); 00504 buffer += delta; 00505 result += delta; 00506 zip->cursor += delta; 00507 zip->pos += delta; 00508 00509 count -= delta; 00510 if ( count == 0 ) 00511 break; 00512 00513 error = ft_gzip_file_fill_output( zip ); 00514 if ( error ) 00515 break; 00516 } 00517 00518 Exit: 00519 return result; 00520 } 00521 00522 00523 /***************************************************************************/ 00524 /***************************************************************************/ 00525 /***** *****/ 00526 /***** G Z E M B E D D I N G S T R E A M *****/ 00527 /***** *****/ 00528 /***************************************************************************/ 00529 /***************************************************************************/ 00530 00531 static void 00532 ft_gzip_stream_close( FT_Stream stream ) 00533 { 00534 FT_GZipFile zip = (FT_GZipFile)stream->descriptor.pointer; 00535 FT_Memory memory = stream->memory; 00536 00537 00538 if ( zip ) 00539 { 00540 /* finalize gzip file descriptor */ 00541 ft_gzip_file_done( zip ); 00542 00543 FT_FREE( zip ); 00544 00545 stream->descriptor.pointer = NULL; 00546 } 00547 } 00548 00549 00550 static FT_ULong 00551 ft_gzip_stream_io( FT_Stream stream, 00552 FT_ULong pos, 00553 FT_Byte* buffer, 00554 FT_ULong count ) 00555 { 00556 FT_GZipFile zip = (FT_GZipFile)stream->descriptor.pointer; 00557 00558 00559 return ft_gzip_file_io( zip, pos, buffer, count ); 00560 } 00561 00562 00563 static FT_ULong 00564 ft_gzip_get_uncompressed_size( FT_Stream stream ) 00565 { 00566 FT_Error error; 00567 FT_ULong old_pos; 00568 FT_ULong result = 0; 00569 00570 00571 old_pos = stream->pos; 00572 if ( !FT_Stream_Seek( stream, stream->size - 4 ) ) 00573 { 00574 result = (FT_ULong)FT_Stream_ReadLong( stream, &error ); 00575 if ( error ) 00576 result = 0; 00577 00578 (void)FT_Stream_Seek( stream, old_pos ); 00579 } 00580 00581 return result; 00582 } 00583 00584 00585 FT_EXPORT_DEF( FT_Error ) 00586 FT_Stream_OpenGzip( FT_Stream stream, 00587 FT_Stream source ) 00588 { 00589 FT_Error error; 00590 FT_Memory memory = source->memory; 00591 FT_GZipFile zip; 00592 00593 00594 /* 00595 * check the header right now; this prevents allocating un-necessary 00596 * objects when we don't need them 00597 */ 00598 error = ft_gzip_check_header( source ); 00599 if ( error ) 00600 goto Exit; 00601 00602 FT_ZERO( stream ); 00603 stream->memory = memory; 00604 00605 if ( !FT_QNEW( zip ) ) 00606 { 00607 error = ft_gzip_file_init( zip, stream, source ); 00608 if ( error ) 00609 { 00610 FT_FREE( zip ); 00611 goto Exit; 00612 } 00613 00614 stream->descriptor.pointer = zip; 00615 } 00616 00617 /* 00618 * We use the following trick to try to dramatically improve the 00619 * performance while dealing with small files. If the original stream 00620 * size is less than a certain threshold, we try to load the whole font 00621 * file into memory. This saves us from using the 32KB buffer needed 00622 * to inflate the file, plus the two 4KB intermediate input/output 00623 * buffers used in the `FT_GZipFile' structure. 00624 */ 00625 { 00626 FT_ULong zip_size = ft_gzip_get_uncompressed_size( source ); 00627 00628 00629 if ( zip_size != 0 && zip_size < 40 * 1024 ) 00630 { 00631 FT_Byte* zip_buff; 00632 00633 00634 if ( !FT_ALLOC( zip_buff, zip_size ) ) 00635 { 00636 FT_ULong count; 00637 00638 00639 count = ft_gzip_file_io( zip, 0, zip_buff, zip_size ); 00640 if ( count == zip_size ) 00641 { 00642 ft_gzip_file_done( zip ); 00643 FT_FREE( zip ); 00644 00645 stream->descriptor.pointer = NULL; 00646 00647 stream->size = zip_size; 00648 stream->pos = 0; 00649 stream->base = zip_buff; 00650 stream->read = NULL; 00651 stream->close = ft_gzip_stream_close; 00652 00653 goto Exit; 00654 } 00655 00656 ft_gzip_file_io( zip, 0, NULL, 0 ); 00657 FT_FREE( zip_buff ); 00658 } 00659 error = Gzip_Err_Ok; 00660 } 00661 } 00662 00663 stream->size = 0x7FFFFFFFL; /* don't know the real size! */ 00664 stream->pos = 0; 00665 stream->base = 0; 00666 stream->read = ft_gzip_stream_io; 00667 stream->close = ft_gzip_stream_close; 00668 00669 Exit: 00670 return error; 00671 } 00672 00673 #else /* !FT_CONFIG_OPTION_USE_ZLIB */ 00674 00675 FT_EXPORT_DEF( FT_Error ) 00676 FT_Stream_OpenGzip( FT_Stream stream, 00677 FT_Stream source ) 00678 { 00679 FT_UNUSED( stream ); 00680 FT_UNUSED( source ); 00681 00682 return Gzip_Err_Unimplemented_Feature; 00683 } 00684 00685 #endif /* !FT_CONFIG_OPTION_USE_ZLIB */ 00686 00687 00688 /* END */ Generated on Sun May 27 2012 04:33:51 for ReactOS by
1.7.6.1
|