1 /***************************************************************************/
5 /* FreeType support for .bz2 compressed files. */
7 /* This optional component relies on libbz2. It should mainly be used to */
8 /* parse compressed PCF fonts, as found with many X11 server */
11 /* Copyright 2010, 2012 by */
14 /* Based on src/gzip/ftgzip.c, Copyright 2002 - 2010 by */
15 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
17 /* This file is part of the FreeType project, and may only be used, */
18 /* modified, and distributed under the terms of the FreeType project */
19 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
20 /* this file you indicate that you have read the license and */
21 /* understand and accept it fully. */
23 /***************************************************************************/
27 #include FT_INTERNAL_MEMORY_H
28 #include FT_INTERNAL_STREAM_H
29 #include FT_INTERNAL_DEBUG_H
31 #include FT_CONFIG_STANDARD_LIBRARY_H
34 #include FT_MODULE_ERRORS_H
39 #define FT_ERR_PREFIX Bzip2_Err_
40 #define FT_ERR_BASE FT_Mod_Err_Bzip2
45 #ifdef FT_CONFIG_OPTION_USE_BZIP2
47 #ifdef FT_CONFIG_OPTION_PIC
48 #error "bzip2 code does not support PIC yet"
51 #define BZ_NO_STDIO /* Do not need FILE */
55 /***************************************************************************/
56 /***************************************************************************/
58 /***** B Z I P 2 M E M O R Y M A N A G E M E N T *****/
60 /***************************************************************************/
61 /***************************************************************************/
63 /* it is better to use FreeType memory routines instead of raw
66 typedef void *(* alloc_func)(void*, int, int);
67 typedef void (* free_func)(void*, void*);
70 ft_bzip2_alloc( FT_Memory memory,
74 FT_ULong sz = (FT_ULong)size * items;
79 (void)FT_ALLOC( p, sz );
85 ft_bzip2_free( FT_Memory memory,
88 FT_MEM_FREE( address );
92 /***************************************************************************/
93 /***************************************************************************/
95 /***** B Z I P 2 F I L E D E S C R I P T O R *****/
97 /***************************************************************************/
98 /***************************************************************************/
100 #define FT_BZIP2_BUFFER_SIZE 4096
102 typedef struct FT_BZip2FileRec_
104 FT_Stream source; /* parent/source stream */
105 FT_Stream stream; /* embedding stream */
106 FT_Memory memory; /* memory allocator */
107 bz_stream bzstream; /* bzlib input stream */
109 FT_Byte input[FT_BZIP2_BUFFER_SIZE]; /* input read buffer */
111 FT_Byte buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer */
112 FT_ULong pos; /* position in output */
116 } FT_BZip2FileRec, *FT_BZip2File;
119 /* check and skip .bz2 header - we don't support `transparent' compression */
121 ft_bzip2_check_header( FT_Stream stream )
123 FT_Error error = Bzip2_Err_Ok;
127 if ( FT_STREAM_SEEK( 0 ) ||
128 FT_STREAM_READ( head, 4 ) )
131 /* head[0] && head[1] are the magic numbers; */
132 /* head[2] is the version, and head[3] the blocksize */
133 if ( head[0] != 0x42 ||
135 head[2] != 0x68 ) /* only support bzip2 (huffman) */
137 error = Bzip2_Err_Invalid_File_Format;
147 ft_bzip2_file_init( FT_BZip2File zip,
151 bz_stream* bzstream = &zip->bzstream;
152 FT_Error error = Bzip2_Err_Ok;
155 zip->stream = stream;
156 zip->source = source;
157 zip->memory = stream->memory;
159 zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE;
160 zip->cursor = zip->limit;
163 /* check .bz2 header */
167 error = ft_bzip2_check_header( stream );
171 if ( FT_STREAM_SEEK( 0 ) )
175 /* initialize bzlib */
176 bzstream->bzalloc = (alloc_func)ft_bzip2_alloc;
177 bzstream->bzfree = (free_func) ft_bzip2_free;
178 bzstream->opaque = zip->memory;
180 bzstream->avail_in = 0;
181 bzstream->next_in = (char*)zip->buffer;
183 if ( BZ2_bzDecompressInit( bzstream, 0, 0 ) != BZ_OK ||
184 bzstream->next_in == NULL )
185 error = Bzip2_Err_Invalid_File_Format;
193 ft_bzip2_file_done( FT_BZip2File zip )
195 bz_stream* bzstream = &zip->bzstream;
198 BZ2_bzDecompressEnd( bzstream );
201 bzstream->bzalloc = NULL;
202 bzstream->bzfree = NULL;
203 bzstream->opaque = NULL;
204 bzstream->next_in = NULL;
205 bzstream->next_out = NULL;
206 bzstream->avail_in = 0;
207 bzstream->avail_out = 0;
216 ft_bzip2_file_reset( FT_BZip2File zip )
218 FT_Stream stream = zip->source;
222 if ( !FT_STREAM_SEEK( 0 ) )
224 bz_stream* bzstream = &zip->bzstream;
227 BZ2_bzDecompressEnd( bzstream );
229 bzstream->avail_in = 0;
230 bzstream->next_in = (char*)zip->input;
231 bzstream->avail_out = 0;
232 bzstream->next_out = (char*)zip->buffer;
234 zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE;
235 zip->cursor = zip->limit;
238 BZ2_bzDecompressInit( bzstream, 0, 0 );
246 ft_bzip2_file_fill_input( FT_BZip2File zip )
248 bz_stream* bzstream = &zip->bzstream;
249 FT_Stream stream = zip->source;
255 size = stream->read( stream, stream->pos, zip->input,
256 FT_BZIP2_BUFFER_SIZE );
258 return Bzip2_Err_Invalid_Stream_Operation;
262 size = stream->size - stream->pos;
263 if ( size > FT_BZIP2_BUFFER_SIZE )
264 size = FT_BZIP2_BUFFER_SIZE;
267 return Bzip2_Err_Invalid_Stream_Operation;
269 FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
273 bzstream->next_in = (char*)zip->input;
274 bzstream->avail_in = size;
281 ft_bzip2_file_fill_output( FT_BZip2File zip )
283 bz_stream* bzstream = &zip->bzstream;
284 FT_Error error = Bzip2_Err_Ok;
287 zip->cursor = zip->buffer;
288 bzstream->next_out = (char*)zip->cursor;
289 bzstream->avail_out = FT_BZIP2_BUFFER_SIZE;
291 while ( bzstream->avail_out > 0 )
296 if ( bzstream->avail_in == 0 )
298 error = ft_bzip2_file_fill_input( zip );
303 err = BZ2_bzDecompress( bzstream );
305 if ( err == BZ_STREAM_END )
307 zip->limit = (FT_Byte*)bzstream->next_out;
308 if ( zip->limit == zip->cursor )
309 error = Bzip2_Err_Invalid_Stream_Operation;
312 else if ( err != BZ_OK )
314 error = Bzip2_Err_Invalid_Stream_Operation;
323 /* fill output buffer; `count' must be <= FT_BZIP2_BUFFER_SIZE */
325 ft_bzip2_file_skip_output( FT_BZip2File zip,
328 FT_Error error = Bzip2_Err_Ok;
334 delta = (FT_ULong)( zip->limit - zip->cursor );
335 if ( delta >= count )
338 zip->cursor += delta;
345 error = ft_bzip2_file_fill_output( zip );
355 ft_bzip2_file_io( FT_BZip2File zip,
364 /* Reset inflate stream if we're seeking backwards. */
365 /* Yes, that is not too efficient, but it saves memory :-) */
366 if ( pos < zip->pos )
368 error = ft_bzip2_file_reset( zip );
373 /* skip unwanted bytes */
374 if ( pos > zip->pos )
376 error = ft_bzip2_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
384 /* now read the data */
390 delta = (FT_ULong)( zip->limit - zip->cursor );
391 if ( delta >= count )
394 FT_MEM_COPY( buffer, zip->cursor, delta );
397 zip->cursor += delta;
404 error = ft_bzip2_file_fill_output( zip );
414 /***************************************************************************/
415 /***************************************************************************/
417 /***** B Z E M B E D D I N G S T R E A M *****/
419 /***************************************************************************/
420 /***************************************************************************/
423 ft_bzip2_stream_close( FT_Stream stream )
425 FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer;
426 FT_Memory memory = stream->memory;
431 /* finalize bzip file descriptor */
432 ft_bzip2_file_done( zip );
436 stream->descriptor.pointer = NULL;
442 ft_bzip2_stream_io( FT_Stream stream,
447 FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer;
450 return ft_bzip2_file_io( zip, pos, buffer, count );
454 FT_EXPORT_DEF( FT_Error )
455 FT_Stream_OpenBzip2( FT_Stream stream,
459 FT_Memory memory = source->memory;
460 FT_BZip2File zip = NULL;
464 * check the header right now; this prevents allocating unnecessary
465 * objects when we don't need them
467 error = ft_bzip2_check_header( source );
472 stream->memory = memory;
474 if ( !FT_QNEW( zip ) )
476 error = ft_bzip2_file_init( zip, stream, source );
483 stream->descriptor.pointer = zip;
486 stream->size = 0x7FFFFFFFL; /* don't know the real size! */
489 stream->read = ft_bzip2_stream_io;
490 stream->close = ft_bzip2_stream_close;
496 #else /* !FT_CONFIG_OPTION_USE_BZIP2 */
498 FT_EXPORT_DEF( FT_Error )
499 FT_Stream_OpenBzip2( FT_Stream stream,
505 return Bzip2_Err_Unimplemented_Feature;
508 #endif /* !FT_CONFIG_OPTION_USE_BZIP2 */