d7a64576baddf7958152bb1385de4c7d02ba672b
[platform/upstream/freetype2.git] / src / lzw / ftzopen.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftzopen.c                                                              */
4 /*                                                                         */
5 /*    FreeType support for .Z compressed files.                            */
6 /*                                                                         */
7 /*  This optional component relies on NetBSD's zopen().  It should mainly  */
8 /*  be used to parse compressed PCF fonts, as found with many X11 server   */
9 /*  distributions.                                                         */
10 /*                                                                         */
11 /*  Copyright 2005-2007, 2009, 2011 by David Turner.                       */
12 /*                                                                         */
13 /*  This file is part of the FreeType project, and may only be used,       */
14 /*  modified, and distributed under the terms of the FreeType project      */
15 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
16 /*  this file you indicate that you have read the license and              */
17 /*  understand and accept it fully.                                        */
18 /*                                                                         */
19 /***************************************************************************/
20
21 #include "ftzopen.h"
22 #include FT_INTERNAL_MEMORY_H
23 #include FT_INTERNAL_STREAM_H
24 #include FT_INTERNAL_DEBUG_H
25
26
27   static int
28   ft_lzwstate_refill( FT_LzwState  state )
29   {
30     FT_ULong  count;
31
32
33     if ( state->in_eof )
34       return -1;
35
36     count = FT_Stream_TryRead( state->source,
37                                state->buf_tab,
38                                state->num_bits );  /* WHY? */
39
40     state->buf_size   = (FT_UInt)count;
41     state->buf_total += count;
42     state->in_eof     = FT_BOOL( count < state->num_bits );
43     state->buf_offset = 0;
44     state->buf_size   = ( state->buf_size << 3 ) - ( state->num_bits - 1 );
45
46     if ( count == 0 )  /* end of file */
47       return -1;
48
49     return 0;
50   }
51
52
53   static FT_Int32
54   ft_lzwstate_get_code( FT_LzwState  state )
55   {
56     FT_UInt   num_bits = state->num_bits;
57     FT_Int    offset   = state->buf_offset;
58     FT_Byte*  p;
59     FT_Int    result;
60
61
62     if ( state->buf_clear                    ||
63          offset >= state->buf_size           ||
64          state->free_ent >= state->free_bits )
65     {
66       if ( state->free_ent >= state->free_bits )
67       {
68         state->num_bits  = ++num_bits;
69         state->free_bits = state->num_bits < state->max_bits
70                            ? (FT_UInt)( ( 1UL << num_bits ) - 256 )
71                            : state->max_free + 1;
72       }
73
74       if ( state->buf_clear )
75       {
76         state->num_bits  = num_bits = LZW_INIT_BITS;
77         state->free_bits = (FT_UInt)( ( 1UL << num_bits ) - 256 );
78         state->buf_clear = 0;
79       }
80
81       if ( ft_lzwstate_refill( state ) < 0 )
82         return -1;
83
84       offset = 0;
85     }
86
87     state->buf_offset = offset + num_bits;
88
89     p         = &state->buf_tab[offset >> 3];
90     offset   &= 7;
91     result    = *p++ >> offset;
92     offset    = 8 - offset;
93     num_bits -= offset;
94
95     if ( num_bits >= 8 )
96     {
97       result   |= *p++ << offset;
98       offset   += 8;
99       num_bits -= 8;
100     }
101     if ( num_bits > 0 )
102       result |= ( *p & LZW_MASK( num_bits ) ) << offset;
103
104     return result;
105   }
106
107
108   /* grow the character stack */
109   static int
110   ft_lzwstate_stack_grow( FT_LzwState  state )
111   {
112     if ( state->stack_top >= state->stack_size )
113     {
114       FT_Memory  memory = state->memory;
115       FT_Error   error;
116       FT_Offset  old_size = state->stack_size;
117       FT_Offset  new_size = old_size;
118
119       new_size = new_size + ( new_size >> 1 ) + 4;
120
121       if ( state->stack == state->stack_0 )
122       {
123         state->stack = NULL;
124         old_size     = 0;
125       }
126
127       /* requirement of the character stack larger than 1<<LZW_MAX_BITS */
128       /* implies bug in the decompression code                          */
129       if ( new_size > ( 1 << LZW_MAX_BITS ) )
130       {
131         new_size = 1 << LZW_MAX_BITS;
132         if ( new_size == old_size )
133           return -1;
134       }
135
136       if ( FT_RENEW_ARRAY( state->stack, old_size, new_size ) )
137         return -1;
138
139       state->stack_size = new_size;
140     }
141     return 0;
142   }
143
144
145   /* grow the prefix/suffix arrays */
146   static int
147   ft_lzwstate_prefix_grow( FT_LzwState  state )
148   {
149     FT_UInt    old_size = state->prefix_size;
150     FT_UInt    new_size = old_size;
151     FT_Memory  memory   = state->memory;
152     FT_Error   error;
153
154
155     if ( new_size == 0 )  /* first allocation -> 9 bits */
156       new_size = 512;
157     else
158       new_size += new_size >> 2;  /* don't grow too fast */
159
160     /*
161      *  Note that the `suffix' array is located in the same memory block
162      *  pointed to by `prefix'.
163      *
164      *  I know that sizeof(FT_Byte) == 1 by definition, but it is clearer
165      *  to write it literally.
166      *
167      */
168     if ( FT_REALLOC_MULT( state->prefix, old_size, new_size,
169                           sizeof ( FT_UShort ) + sizeof ( FT_Byte ) ) )
170       return -1;
171
172     /* now adjust `suffix' and move the data accordingly */
173     state->suffix = (FT_Byte*)( state->prefix + new_size );
174
175     FT_MEM_MOVE( state->suffix,
176                  state->prefix + old_size,
177                  old_size * sizeof ( FT_Byte ) );
178
179     state->prefix_size = new_size;
180     return 0;
181   }
182
183
184   FT_LOCAL_DEF( void )
185   ft_lzwstate_reset( FT_LzwState  state )
186   {
187     state->in_eof     = 0;
188     state->buf_offset = 0;
189     state->buf_size   = 0;
190     state->buf_clear  = 0;
191     state->buf_total  = 0;
192     state->stack_top  = 0;
193     state->num_bits   = LZW_INIT_BITS;
194     state->phase      = FT_LZW_PHASE_START;
195   }
196
197
198   FT_LOCAL_DEF( void )
199   ft_lzwstate_init( FT_LzwState  state,
200                     FT_Stream    source )
201   {
202     FT_ZERO( state );
203
204     state->source = source;
205     state->memory = source->memory;
206
207     state->prefix      = NULL;
208     state->suffix      = NULL;
209     state->prefix_size = 0;
210
211     state->stack      = state->stack_0;
212     state->stack_size = sizeof ( state->stack_0 );
213
214     ft_lzwstate_reset( state );
215   }
216
217
218   FT_LOCAL_DEF( void )
219   ft_lzwstate_done( FT_LzwState  state )
220   {
221     FT_Memory  memory = state->memory;
222
223
224     ft_lzwstate_reset( state );
225
226     if ( state->stack != state->stack_0 )
227       FT_FREE( state->stack );
228
229     FT_FREE( state->prefix );
230     state->suffix = NULL;
231
232     FT_ZERO( state );
233   }
234
235
236 #define FTLZW_STACK_PUSH( c )                        \
237   FT_BEGIN_STMNT                                     \
238     if ( state->stack_top >= state->stack_size &&    \
239          ft_lzwstate_stack_grow( state ) < 0   )     \
240       goto Eof;                                      \
241                                                      \
242     state->stack[state->stack_top++] = (FT_Byte)(c); \
243   FT_END_STMNT
244
245
246   FT_LOCAL_DEF( FT_ULong )
247   ft_lzwstate_io( FT_LzwState  state,
248                   FT_Byte*     buffer,
249                   FT_ULong     out_size )
250   {
251     FT_ULong  result = 0;
252
253     FT_UInt  old_char = state->old_char;
254     FT_UInt  old_code = state->old_code;
255     FT_UInt  in_code  = state->in_code;
256
257
258     if ( out_size == 0 )
259       goto Exit;
260
261     switch ( state->phase )
262     {
263     case FT_LZW_PHASE_START:
264       {
265         FT_Byte   max_bits;
266         FT_Int32  c;
267
268
269         /* skip magic bytes, and read max_bits + block_flag */
270         if ( FT_Stream_Seek( state->source, 2 ) != 0               ||
271              FT_Stream_TryRead( state->source, &max_bits, 1 ) != 1 )
272           goto Eof;
273
274         state->max_bits   = max_bits & LZW_BIT_MASK;
275         state->block_mode = max_bits & LZW_BLOCK_MASK;
276         state->max_free   = (FT_UInt)( ( 1UL << state->max_bits ) - 256 );
277
278         if ( state->max_bits > LZW_MAX_BITS )
279           goto Eof;
280
281         state->num_bits = LZW_INIT_BITS;
282         state->free_ent = ( state->block_mode ? LZW_FIRST
283                                               : LZW_CLEAR ) - 256;
284         in_code  = 0;
285
286         state->free_bits = state->num_bits < state->max_bits
287                            ? (FT_UInt)( ( 1UL << state->num_bits ) - 256 )
288                            : state->max_free + 1;
289
290         c = ft_lzwstate_get_code( state );
291         if ( c < 0 || c > 255 )
292           goto Eof;
293
294         old_code = old_char = (FT_UInt)c;
295
296         if ( buffer )
297           buffer[result] = (FT_Byte)old_char;
298
299         if ( ++result >= out_size )
300           goto Exit;
301
302         state->phase = FT_LZW_PHASE_CODE;
303       }
304       /* fall-through */
305
306     case FT_LZW_PHASE_CODE:
307       {
308         FT_Int32  c;
309         FT_UInt   code;
310
311
312       NextCode:
313         c = ft_lzwstate_get_code( state );
314         if ( c < 0 )
315           goto Eof;
316
317         code = (FT_UInt)c;
318
319         if ( code == LZW_CLEAR && state->block_mode )
320         {
321           /* why not LZW_FIRST-256 ? */
322           state->free_ent  = ( LZW_FIRST - 1 ) - 256;
323           state->buf_clear = 1;
324
325           /* not quite right, but at least more predictable */
326           old_code = 0;
327           old_char = 0;
328
329           goto NextCode;
330         }
331
332         in_code = code; /* save code for later */
333
334         if ( code >= 256U )
335         {
336           /* special case for KwKwKwK */
337           if ( code - 256U >= state->free_ent )
338           {
339             /* corrupted LZW stream */
340             if ( code - 256U > state->free_ent )
341               goto Eof;
342
343             FTLZW_STACK_PUSH( old_char );
344             code = old_code;
345           }
346
347           while ( code >= 256U )
348           {
349             if ( !state->prefix )
350               goto Eof;
351
352             FTLZW_STACK_PUSH( state->suffix[code - 256] );
353             code = state->prefix[code - 256];
354           }
355         }
356
357         old_char = code;
358         FTLZW_STACK_PUSH( old_char );
359
360         state->phase = FT_LZW_PHASE_STACK;
361       }
362       /* fall-through */
363
364     case FT_LZW_PHASE_STACK:
365       {
366         while ( state->stack_top > 0 )
367         {
368           --state->stack_top;
369
370           if ( buffer )
371             buffer[result] = state->stack[state->stack_top];
372
373           if ( ++result == out_size )
374             goto Exit;
375         }
376
377         /* now create new entry */
378         if ( state->free_ent < state->max_free )
379         {
380           if ( state->free_ent >= state->prefix_size &&
381                ft_lzwstate_prefix_grow( state ) < 0  )
382             goto Eof;
383
384           FT_ASSERT( state->free_ent < state->prefix_size );
385
386           state->prefix[state->free_ent] = (FT_UShort)old_code;
387           state->suffix[state->free_ent] = (FT_Byte)  old_char;
388
389           state->free_ent += 1;
390         }
391
392         old_code = in_code;
393
394         state->phase = FT_LZW_PHASE_CODE;
395         goto NextCode;
396       }
397
398     default:  /* state == EOF */
399       ;
400     }
401
402   Exit:
403     state->old_code = old_code;
404     state->old_char = old_char;
405     state->in_code  = in_code;
406
407     return result;
408
409   Eof:
410     state->phase = FT_LZW_PHASE_EOF;
411     goto Exit;
412   }
413
414
415 /* END */