Initialize Tizen 2.3
[framework/graphics/freetype.git] / src / bzip2 / ftbzip2.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftbzip2.c                                                              */
4 /*                                                                         */
5 /*    FreeType support for .bz2 compressed files.                          */
6 /*                                                                         */
7 /*  This optional component relies on libbz2.  It should mainly be used to */
8 /*  parse compressed PCF fonts, as found with many X11 server              */
9 /*  distributions.                                                         */
10 /*                                                                         */
11 /*  Copyright 2010, 2012 by                                                */
12 /*  Joel Klinghed.                                                         */
13 /*                                                                         */
14 /*  Based on src/gzip/ftgzip.c, Copyright 2002 - 2010 by                   */
15 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
16 /*                                                                         */
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.                                        */
22 /*                                                                         */
23 /***************************************************************************/
24
25
26 #include <ft2build.h>
27 #include FT_INTERNAL_MEMORY_H
28 #include FT_INTERNAL_STREAM_H
29 #include FT_INTERNAL_DEBUG_H
30 #include FT_BZIP2_H
31 #include FT_CONFIG_STANDARD_LIBRARY_H
32
33
34 #include FT_MODULE_ERRORS_H
35
36 #undef __FTERRORS_H__
37
38 #undef  FT_ERR_PREFIX
39 #define FT_ERR_PREFIX  Bzip2_Err_
40 #define FT_ERR_BASE    FT_Mod_Err_Bzip2
41
42 #include FT_ERRORS_H
43
44
45 #ifdef FT_CONFIG_OPTION_USE_BZIP2
46
47 #ifdef FT_CONFIG_OPTION_PIC
48 #error "bzip2 code does not support PIC yet"
49 #endif
50
51 #define BZ_NO_STDIO /* Do not need FILE */
52 #include <bzlib.h>
53
54
55 /***************************************************************************/
56 /***************************************************************************/
57 /*****                                                                 *****/
58 /*****           B Z I P 2   M E M O R Y   M A N A G E M E N T         *****/
59 /*****                                                                 *****/
60 /***************************************************************************/
61 /***************************************************************************/
62
63   /* it is better to use FreeType memory routines instead of raw
64      'malloc/free' */
65
66   typedef void *(* alloc_func)(void*, int, int);
67   typedef void (* free_func)(void*, void*);
68
69   static void*
70   ft_bzip2_alloc( FT_Memory  memory,
71                   int        items,
72                   int        size )
73   {
74     FT_ULong    sz = (FT_ULong)size * items;
75     FT_Error    error;
76     FT_Pointer  p  = NULL;
77
78
79     (void)FT_ALLOC( p, sz );
80     return p;
81   }
82
83
84   static void
85   ft_bzip2_free( FT_Memory  memory,
86                  void*      address )
87   {
88     FT_MEM_FREE( address );
89   }
90
91
92 /***************************************************************************/
93 /***************************************************************************/
94 /*****                                                                 *****/
95 /*****              B Z I P 2   F I L E   D E S C R I P T O R          *****/
96 /*****                                                                 *****/
97 /***************************************************************************/
98 /***************************************************************************/
99
100 #define FT_BZIP2_BUFFER_SIZE  4096
101
102   typedef struct  FT_BZip2FileRec_
103   {
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          */
108
109     FT_Byte    input[FT_BZIP2_BUFFER_SIZE];  /* input read buffer  */
110
111     FT_Byte    buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer      */
112     FT_ULong   pos;                          /* position in output */
113     FT_Byte*   cursor;
114     FT_Byte*   limit;
115
116   } FT_BZip2FileRec, *FT_BZip2File;
117
118
119   /* check and skip .bz2 header - we don't support `transparent' compression */
120   static FT_Error
121   ft_bzip2_check_header( FT_Stream  stream )
122   {
123     FT_Error  error = Bzip2_Err_Ok;
124     FT_Byte   head[4];
125
126
127     if ( FT_STREAM_SEEK( 0 )       ||
128          FT_STREAM_READ( head, 4 ) )
129       goto Exit;
130
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  ||
134          head[1] != 0x5a  ||
135          head[2] != 0x68  )  /* only support bzip2 (huffman) */
136     {
137       error = Bzip2_Err_Invalid_File_Format;
138       goto Exit;
139     }
140
141   Exit:
142     return error;
143   }
144
145
146   static FT_Error
147   ft_bzip2_file_init( FT_BZip2File  zip,
148                       FT_Stream     stream,
149                       FT_Stream     source )
150   {
151     bz_stream*  bzstream = &zip->bzstream;
152     FT_Error    error    = Bzip2_Err_Ok;
153
154
155     zip->stream = stream;
156     zip->source = source;
157     zip->memory = stream->memory;
158
159     zip->limit  = zip->buffer + FT_BZIP2_BUFFER_SIZE;
160     zip->cursor = zip->limit;
161     zip->pos    = 0;
162
163     /* check .bz2 header */
164     {
165       stream = source;
166
167       error = ft_bzip2_check_header( stream );
168       if ( error )
169         goto Exit;
170
171       if ( FT_STREAM_SEEK( 0 ) )
172         goto Exit;
173     }
174
175     /* initialize bzlib */
176     bzstream->bzalloc = (alloc_func)ft_bzip2_alloc;
177     bzstream->bzfree  = (free_func) ft_bzip2_free;
178     bzstream->opaque  = zip->memory;
179
180     bzstream->avail_in = 0;
181     bzstream->next_in  = (char*)zip->buffer;
182
183     if ( BZ2_bzDecompressInit( bzstream, 0, 0 ) != BZ_OK ||
184          bzstream->next_in == NULL                       )
185       error = Bzip2_Err_Invalid_File_Format;
186
187   Exit:
188     return error;
189   }
190
191
192   static void
193   ft_bzip2_file_done( FT_BZip2File  zip )
194   {
195     bz_stream*  bzstream = &zip->bzstream;
196
197
198     BZ2_bzDecompressEnd( bzstream );
199
200     /* clear the rest */
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;
208
209     zip->memory = NULL;
210     zip->source = NULL;
211     zip->stream = NULL;
212   }
213
214
215   static FT_Error
216   ft_bzip2_file_reset( FT_BZip2File  zip )
217   {
218     FT_Stream  stream = zip->source;
219     FT_Error   error;
220
221
222     if ( !FT_STREAM_SEEK( 0 ) )
223     {
224       bz_stream*  bzstream = &zip->bzstream;
225
226
227       BZ2_bzDecompressEnd( bzstream );
228
229       bzstream->avail_in  = 0;
230       bzstream->next_in   = (char*)zip->input;
231       bzstream->avail_out = 0;
232       bzstream->next_out  = (char*)zip->buffer;
233
234       zip->limit  = zip->buffer + FT_BZIP2_BUFFER_SIZE;
235       zip->cursor = zip->limit;
236       zip->pos    = 0;
237
238       BZ2_bzDecompressInit( bzstream, 0, 0 );
239     }
240
241     return error;
242   }
243
244
245   static FT_Error
246   ft_bzip2_file_fill_input( FT_BZip2File  zip )
247   {
248     bz_stream*  bzstream = &zip->bzstream;
249     FT_Stream   stream    = zip->source;
250     FT_ULong    size;
251
252
253     if ( stream->read )
254     {
255       size = stream->read( stream, stream->pos, zip->input,
256                            FT_BZIP2_BUFFER_SIZE );
257       if ( size == 0 )
258         return Bzip2_Err_Invalid_Stream_Operation;
259     }
260     else
261     {
262       size = stream->size - stream->pos;
263       if ( size > FT_BZIP2_BUFFER_SIZE )
264         size = FT_BZIP2_BUFFER_SIZE;
265
266       if ( size == 0 )
267         return Bzip2_Err_Invalid_Stream_Operation;
268
269       FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
270     }
271     stream->pos += size;
272
273     bzstream->next_in  = (char*)zip->input;
274     bzstream->avail_in = size;
275
276     return Bzip2_Err_Ok;
277   }
278
279
280   static FT_Error
281   ft_bzip2_file_fill_output( FT_BZip2File  zip )
282   {
283     bz_stream*  bzstream = &zip->bzstream;
284     FT_Error    error    = Bzip2_Err_Ok;
285
286
287     zip->cursor         = zip->buffer;
288     bzstream->next_out  = (char*)zip->cursor;
289     bzstream->avail_out = FT_BZIP2_BUFFER_SIZE;
290
291     while ( bzstream->avail_out > 0 )
292     {
293       int  err;
294
295
296       if ( bzstream->avail_in == 0 )
297       {
298         error = ft_bzip2_file_fill_input( zip );
299         if ( error )
300           break;
301       }
302
303       err = BZ2_bzDecompress( bzstream );
304
305       if ( err == BZ_STREAM_END )
306       {
307         zip->limit = (FT_Byte*)bzstream->next_out;
308         if ( zip->limit == zip->cursor )
309           error = Bzip2_Err_Invalid_Stream_Operation;
310         break;
311       }
312       else if ( err != BZ_OK )
313       {
314         error = Bzip2_Err_Invalid_Stream_Operation;
315         break;
316       }
317     }
318
319     return error;
320   }
321
322
323   /* fill output buffer; `count' must be <= FT_BZIP2_BUFFER_SIZE */
324   static FT_Error
325   ft_bzip2_file_skip_output( FT_BZip2File  zip,
326                              FT_ULong      count )
327   {
328     FT_Error  error = Bzip2_Err_Ok;
329     FT_ULong  delta;
330
331
332     for (;;)
333     {
334       delta = (FT_ULong)( zip->limit - zip->cursor );
335       if ( delta >= count )
336         delta = count;
337
338       zip->cursor += delta;
339       zip->pos    += delta;
340
341       count -= delta;
342       if ( count == 0 )
343         break;
344
345       error = ft_bzip2_file_fill_output( zip );
346       if ( error )
347         break;
348     }
349
350     return error;
351   }
352
353
354   static FT_ULong
355   ft_bzip2_file_io( FT_BZip2File  zip,
356                     FT_ULong      pos,
357                     FT_Byte*      buffer,
358                     FT_ULong      count )
359   {
360     FT_ULong  result = 0;
361     FT_Error  error;
362
363
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 )
367     {
368       error = ft_bzip2_file_reset( zip );
369       if ( error )
370         goto Exit;
371     }
372
373     /* skip unwanted bytes */
374     if ( pos > zip->pos )
375     {
376       error = ft_bzip2_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
377       if ( error )
378         goto Exit;
379     }
380
381     if ( count == 0 )
382       goto Exit;
383
384     /* now read the data */
385     for (;;)
386     {
387       FT_ULong  delta;
388
389
390       delta = (FT_ULong)( zip->limit - zip->cursor );
391       if ( delta >= count )
392         delta = count;
393
394       FT_MEM_COPY( buffer, zip->cursor, delta );
395       buffer      += delta;
396       result      += delta;
397       zip->cursor += delta;
398       zip->pos    += delta;
399
400       count -= delta;
401       if ( count == 0 )
402         break;
403
404       error = ft_bzip2_file_fill_output( zip );
405       if ( error )
406         break;
407     }
408
409   Exit:
410     return result;
411   }
412
413
414 /***************************************************************************/
415 /***************************************************************************/
416 /*****                                                                 *****/
417 /*****               B Z   E M B E D D I N G   S T R E A M             *****/
418 /*****                                                                 *****/
419 /***************************************************************************/
420 /***************************************************************************/
421
422   static void
423   ft_bzip2_stream_close( FT_Stream  stream )
424   {
425     FT_BZip2File  zip    = (FT_BZip2File)stream->descriptor.pointer;
426     FT_Memory     memory = stream->memory;
427
428
429     if ( zip )
430     {
431       /* finalize bzip file descriptor */
432       ft_bzip2_file_done( zip );
433
434       FT_FREE( zip );
435
436       stream->descriptor.pointer = NULL;
437     }
438   }
439
440
441   static FT_ULong
442   ft_bzip2_stream_io( FT_Stream  stream,
443                       FT_ULong   pos,
444                       FT_Byte*   buffer,
445                       FT_ULong   count )
446   {
447     FT_BZip2File  zip = (FT_BZip2File)stream->descriptor.pointer;
448
449
450     return ft_bzip2_file_io( zip, pos, buffer, count );
451   }
452
453
454   FT_EXPORT_DEF( FT_Error )
455   FT_Stream_OpenBzip2( FT_Stream  stream,
456                        FT_Stream  source )
457   {
458     FT_Error      error;
459     FT_Memory     memory = source->memory;
460     FT_BZip2File  zip = NULL;
461
462
463     /*
464      *  check the header right now; this prevents allocating unnecessary
465      *  objects when we don't need them
466      */
467     error = ft_bzip2_check_header( source );
468     if ( error )
469       goto Exit;
470
471     FT_ZERO( stream );
472     stream->memory = memory;
473
474     if ( !FT_QNEW( zip ) )
475     {
476       error = ft_bzip2_file_init( zip, stream, source );
477       if ( error )
478       {
479         FT_FREE( zip );
480         goto Exit;
481       }
482
483       stream->descriptor.pointer = zip;
484     }
485
486     stream->size  = 0x7FFFFFFFL;  /* don't know the real size! */
487     stream->pos   = 0;
488     stream->base  = 0;
489     stream->read  = ft_bzip2_stream_io;
490     stream->close = ft_bzip2_stream_close;
491
492   Exit:
493     return error;
494   }
495
496 #else  /* !FT_CONFIG_OPTION_USE_BZIP2 */
497
498   FT_EXPORT_DEF( FT_Error )
499   FT_Stream_OpenBzip2( FT_Stream  stream,
500                        FT_Stream  source )
501   {
502     FT_UNUSED( stream );
503     FT_UNUSED( source );
504
505     return Bzip2_Err_Unimplemented_Feature;
506   }
507
508 #endif /* !FT_CONFIG_OPTION_USE_BZIP2 */
509
510
511 /* END */