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 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
38
#define FT_ERR_PREFIX Bzip2_Err_
39
#define FT_ERR_BASE FT_Mod_Err_Bzip2
44
#ifdef FT_CONFIG_OPTION_USE_BZIP2
46
#ifdef FT_CONFIG_OPTION_PIC
47
#error "bzip2 code does not support PIC yet"
50
#define BZ_NO_STDIO /* Do not need FILE */
54
/***************************************************************************/
55
/***************************************************************************/
57
/***** B Z I P 2 M E M O R Y M A N A G E M E N T *****/
59
/***************************************************************************/
60
/***************************************************************************/
62
/* it is better to use FreeType memory routines instead of raw
65
typedef void *(* alloc_func)(void*, int, int);
66
typedef void (* free_func)(void*, void*);
69
ft_bzip2_alloc( FT_Memory memory,
73
FT_ULong sz = (FT_ULong)size * items;
78
(void)FT_ALLOC( p, sz );
84
ft_bzip2_free( FT_Memory memory,
87
FT_MEM_FREE( address );
91
/***************************************************************************/
92
/***************************************************************************/
94
/***** B Z I P 2 F I L E D E S C R I P T O R *****/
96
/***************************************************************************/
97
/***************************************************************************/
99
#define FT_BZIP2_BUFFER_SIZE 4096
101
typedef struct FT_BZip2FileRec_
103
FT_Stream source; /* parent/source stream */
104
FT_Stream stream; /* embedding stream */
105
FT_Memory memory; /* memory allocator */
106
bz_stream bzstream; /* bzlib input stream */
108
FT_Byte input[FT_BZIP2_BUFFER_SIZE]; /* input read buffer */
110
FT_Byte buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer */
111
FT_ULong pos; /* position in output */
115
} FT_BZip2FileRec, *FT_BZip2File;
118
/* check and skip .bz2 header - we don't support `transparent' compression */
120
ft_bzip2_check_header( FT_Stream stream )
122
FT_Error error = Bzip2_Err_Ok;
126
if ( FT_STREAM_SEEK( 0 ) ||
127
FT_STREAM_READ( head, 4 ) )
130
/* head[0] && head[1] are the magic numbers; */
131
/* head[2] is the version, and head[3] the blocksize */
132
if ( head[0] != 0x42 ||
134
head[2] != 0x68 ) /* only support bzip2 (huffman) */
136
error = Bzip2_Err_Invalid_File_Format;
146
ft_bzip2_file_init( FT_BZip2File zip,
150
bz_stream* bzstream = &zip->bzstream;
151
FT_Error error = Bzip2_Err_Ok;
154
zip->stream = stream;
155
zip->source = source;
156
zip->memory = stream->memory;
158
zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE;
159
zip->cursor = zip->limit;
162
/* check .bz2 header */
166
error = ft_bzip2_check_header( stream );
170
if ( FT_STREAM_SEEK( 0 ) )
174
/* initialize bzlib */
175
bzstream->bzalloc = (alloc_func)ft_bzip2_alloc;
176
bzstream->bzfree = (free_func) ft_bzip2_free;
177
bzstream->opaque = zip->memory;
179
bzstream->avail_in = 0;
180
bzstream->next_in = (char*)zip->buffer;
182
if ( BZ2_bzDecompressInit( bzstream, 0, 0 ) != BZ_OK ||
183
bzstream->next_in == NULL )
184
error = Bzip2_Err_Invalid_File_Format;
192
ft_bzip2_file_done( FT_BZip2File zip )
194
bz_stream* bzstream = &zip->bzstream;
197
BZ2_bzDecompressEnd( bzstream );
200
bzstream->bzalloc = NULL;
201
bzstream->bzfree = NULL;
202
bzstream->opaque = NULL;
203
bzstream->next_in = NULL;
204
bzstream->next_out = NULL;
205
bzstream->avail_in = 0;
206
bzstream->avail_out = 0;
215
ft_bzip2_file_reset( FT_BZip2File zip )
217
FT_Stream stream = zip->source;
221
if ( !FT_STREAM_SEEK( 0 ) )
223
bz_stream* bzstream = &zip->bzstream;
226
BZ2_bzDecompressEnd( bzstream );
228
bzstream->avail_in = 0;
229
bzstream->next_in = (char*)zip->input;
230
bzstream->avail_out = 0;
231
bzstream->next_out = (char*)zip->buffer;
233
zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE;
234
zip->cursor = zip->limit;
237
BZ2_bzDecompressInit( bzstream, 0, 0 );
245
ft_bzip2_file_fill_input( FT_BZip2File zip )
247
bz_stream* bzstream = &zip->bzstream;
248
FT_Stream stream = zip->source;
254
size = stream->read( stream, stream->pos, zip->input,
255
FT_BZIP2_BUFFER_SIZE );
257
return Bzip2_Err_Invalid_Stream_Operation;
261
size = stream->size - stream->pos;
262
if ( size > FT_BZIP2_BUFFER_SIZE )
263
size = FT_BZIP2_BUFFER_SIZE;
266
return Bzip2_Err_Invalid_Stream_Operation;
268
FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
272
bzstream->next_in = (char*)zip->input;
273
bzstream->avail_in = size;
280
ft_bzip2_file_fill_output( FT_BZip2File zip )
282
bz_stream* bzstream = &zip->bzstream;
283
FT_Error error = Bzip2_Err_Ok;
286
zip->cursor = zip->buffer;
287
bzstream->next_out = (char*)zip->cursor;
288
bzstream->avail_out = FT_BZIP2_BUFFER_SIZE;
290
while ( bzstream->avail_out > 0 )
295
if ( bzstream->avail_in == 0 )
297
error = ft_bzip2_file_fill_input( zip );
302
err = BZ2_bzDecompress( bzstream );
304
if ( err == BZ_STREAM_END )
306
zip->limit = (FT_Byte*)bzstream->next_out;
307
if ( zip->limit == zip->cursor )
308
error = Bzip2_Err_Invalid_Stream_Operation;
311
else if ( err != BZ_OK )
313
error = Bzip2_Err_Invalid_Stream_Operation;
322
/* fill output buffer; `count' must be <= FT_BZIP2_BUFFER_SIZE */
324
ft_bzip2_file_skip_output( FT_BZip2File zip,
327
FT_Error error = Bzip2_Err_Ok;
333
delta = (FT_ULong)( zip->limit - zip->cursor );
334
if ( delta >= count )
337
zip->cursor += delta;
344
error = ft_bzip2_file_fill_output( zip );
354
ft_bzip2_file_io( FT_BZip2File zip,
363
/* Reset inflate stream if we're seeking backwards. */
364
/* Yes, that is not too efficient, but it saves memory :-) */
365
if ( pos < zip->pos )
367
error = ft_bzip2_file_reset( zip );
372
/* skip unwanted bytes */
373
if ( pos > zip->pos )
375
error = ft_bzip2_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
383
/* now read the data */
389
delta = (FT_ULong)( zip->limit - zip->cursor );
390
if ( delta >= count )
393
FT_MEM_COPY( buffer, zip->cursor, delta );
396
zip->cursor += delta;
403
error = ft_bzip2_file_fill_output( zip );
413
/***************************************************************************/
414
/***************************************************************************/
416
/***** B Z E M B E D D I N G S T R E A M *****/
418
/***************************************************************************/
419
/***************************************************************************/
422
ft_bzip2_stream_close( FT_Stream stream )
424
FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer;
425
FT_Memory memory = stream->memory;
430
/* finalize bzip file descriptor */
431
ft_bzip2_file_done( zip );
435
stream->descriptor.pointer = NULL;
441
ft_bzip2_stream_io( FT_Stream stream,
446
FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer;
449
return ft_bzip2_file_io( zip, pos, buffer, count );
453
FT_EXPORT_DEF( FT_Error )
454
FT_Stream_OpenBzip2( FT_Stream stream,
458
FT_Memory memory = source->memory;
463
* check the header right now; this prevents allocating unnecessary
464
* objects when we don't need them
466
error = ft_bzip2_check_header( source );
471
stream->memory = memory;
473
if ( !FT_QNEW( zip ) )
475
error = ft_bzip2_file_init( zip, stream, source );
482
stream->descriptor.pointer = zip;
485
stream->size = 0x7FFFFFFFL; /* don't know the real size! */
488
stream->read = ft_bzip2_stream_io;
489
stream->close = ft_bzip2_stream_close;
495
#else /* !FT_CONFIG_OPTION_USE_BZIP2 */
497
FT_EXPORT_DEF( FT_Error )
498
FT_Stream_OpenBzip2( FT_Stream stream,
504
return Bzip2_Err_Unimplemented_Feature;
507
#endif /* !FT_CONFIG_OPTION_USE_BZIP2 */