Merge 25584, 25588.
[reactos.git] / reactos / dll / 3rdparty / freetype / src / lzw / ftlzw.c
1 /***************************************************************************/
2 /* */
3 /* ftlzw.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 2004, 2005, 2006 by */
12 /* Albert Chin-A-Young. */
13 /* */
14 /* Based on code in src/gzip/ftgzip.c, Copyright 2004 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 #include <ft2build.h>
26 #include FT_INTERNAL_MEMORY_H
27 #include FT_INTERNAL_STREAM_H
28 #include FT_INTERNAL_DEBUG_H
29 #include FT_LZW_H
30 #include <string.h>
31 #include <stdio.h>
32
33
34 #include FT_MODULE_ERRORS_H
35
36 #undef __FTERRORS_H__
37
38 #define FT_ERR_PREFIX LZW_Err_
39 #define FT_ERR_BASE FT_Mod_Err_LZW
40
41 #include FT_ERRORS_H
42
43
44 #ifdef FT_CONFIG_OPTION_USE_LZW
45
46 #include "ftzopen.h"
47
48
49 /***************************************************************************/
50 /***************************************************************************/
51 /***** *****/
52 /***** M E M O R Y M A N A G E M E N T *****/
53 /***** *****/
54 /***************************************************************************/
55 /***************************************************************************/
56
57 /***************************************************************************/
58 /***************************************************************************/
59 /***** *****/
60 /***** F I L E D E S C R I P T O R *****/
61 /***** *****/
62 /***************************************************************************/
63 /***************************************************************************/
64
65 #define FT_LZW_BUFFER_SIZE 4096
66
67 typedef struct FT_LZWFileRec_
68 {
69 FT_Stream source; /* parent/source stream */
70 FT_Stream stream; /* embedding stream */
71 FT_Memory memory; /* memory allocator */
72 FT_LzwStateRec lzw; /* lzw decompressor state */
73
74 FT_Byte buffer[FT_LZW_BUFFER_SIZE]; /* output buffer */
75 FT_ULong pos; /* position in output */
76 FT_Byte* cursor;
77 FT_Byte* limit;
78
79 } FT_LZWFileRec, *FT_LZWFile;
80
81
82 /* check and skip .Z header */
83 static FT_Error
84 ft_lzw_check_header( FT_Stream stream )
85 {
86 FT_Error error;
87 FT_Byte head[2];
88
89
90 if ( FT_STREAM_SEEK( 0 ) ||
91 FT_STREAM_READ( head, 2 ) )
92 goto Exit;
93
94 /* head[0] && head[1] are the magic numbers */
95 if ( head[0] != 0x1f ||
96 head[1] != 0x9d )
97 error = LZW_Err_Invalid_File_Format;
98
99 Exit:
100 return error;
101 }
102
103
104 static FT_Error
105 ft_lzw_file_init( FT_LZWFile zip,
106 FT_Stream stream,
107 FT_Stream source )
108 {
109 FT_LzwState lzw = &zip->lzw;
110 FT_Error error = LZW_Err_Ok;
111
112
113 zip->stream = stream;
114 zip->source = source;
115 zip->memory = stream->memory;
116
117 zip->limit = zip->buffer + FT_LZW_BUFFER_SIZE;
118 zip->cursor = zip->limit;
119 zip->pos = 0;
120
121 /* check and skip .Z header */
122 {
123 stream = source;
124
125 error = ft_lzw_check_header( source );
126 if ( error )
127 goto Exit;
128 }
129
130 /* initialize internal lzw variable */
131 ft_lzwstate_init( lzw, source );
132
133 Exit:
134 return error;
135 }
136
137
138 static void
139 ft_lzw_file_done( FT_LZWFile zip )
140 {
141 /* clear the rest */
142 ft_lzwstate_done( &zip->lzw );
143
144 zip->memory = NULL;
145 zip->source = NULL;
146 zip->stream = NULL;
147 }
148
149
150 static FT_Error
151 ft_lzw_file_reset( FT_LZWFile zip )
152 {
153 FT_Stream stream = zip->source;
154 FT_Error error;
155
156
157 if ( !FT_STREAM_SEEK( 0 ) )
158 {
159 ft_lzwstate_reset( &zip->lzw );
160
161 zip->limit = zip->buffer + FT_LZW_BUFFER_SIZE;
162 zip->cursor = zip->limit;
163 zip->pos = 0;
164 }
165
166 return error;
167 }
168
169
170 static FT_Error
171 ft_lzw_file_fill_output( FT_LZWFile zip )
172 {
173 FT_LzwState lzw = &zip->lzw;
174 FT_ULong count;
175 FT_Error error = 0;
176
177
178 zip->cursor = zip->buffer;
179
180 count = ft_lzwstate_io( lzw, zip->buffer, FT_LZW_BUFFER_SIZE );
181
182 zip->limit = zip->cursor + count;
183
184 if ( count == 0 )
185 error = LZW_Err_Invalid_Stream_Operation;
186
187 return error;
188 }
189
190
191 /* fill output buffer; `count' must be <= FT_LZW_BUFFER_SIZE */
192 static FT_Error
193 ft_lzw_file_skip_output( FT_LZWFile zip,
194 FT_ULong count )
195 {
196 FT_Error error = LZW_Err_Ok;
197
198
199 /* first, we skip what we can from the output buffer */
200 {
201 FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor );
202
203
204 if ( delta >= count )
205 delta = count;
206
207 zip->cursor += delta;
208 zip->pos += delta;
209
210 count -= delta;
211 }
212
213 /* next, we skip as many bytes remaining as possible */
214 while ( count > 0 )
215 {
216 FT_ULong delta = FT_LZW_BUFFER_SIZE;
217 FT_ULong numread;
218
219
220 if ( delta > count )
221 delta = count;
222
223 numread = ft_lzwstate_io( &zip->lzw, NULL, delta );
224 if ( numread < delta )
225 {
226 /* not enough bytes */
227 error = LZW_Err_Invalid_Stream_Operation;
228 break;
229 }
230
231 zip->pos += delta;
232 count -= delta;
233 }
234
235 return error;
236 }
237
238
239 static FT_ULong
240 ft_lzw_file_io( FT_LZWFile zip,
241 FT_ULong pos,
242 FT_Byte* buffer,
243 FT_ULong count )
244 {
245 FT_ULong result = 0;
246 FT_Error error;
247
248
249 /* seeking backwards. */
250 if ( pos < zip->pos )
251 {
252 /* If the new position is within the output buffer, simply */
253 /* decrement pointers, otherwise we reset the stream completely! */
254 if ( ( zip->pos - pos ) <= (FT_ULong)( zip->cursor - zip->buffer ) )
255 {
256 zip->cursor -= zip->pos - pos;
257 zip->pos = pos;
258 }
259 else
260 {
261 error = ft_lzw_file_reset( zip );
262 if ( error )
263 goto Exit;
264 }
265 }
266
267 /* skip unwanted bytes */
268 if ( pos > zip->pos )
269 {
270 error = ft_lzw_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
271 if ( error )
272 goto Exit;
273 }
274
275 if ( count == 0 )
276 goto Exit;
277
278 /* now read the data */
279 for (;;)
280 {
281 FT_ULong delta;
282
283
284 delta = (FT_ULong)( zip->limit - zip->cursor );
285 if ( delta >= count )
286 delta = count;
287
288 FT_MEM_COPY( buffer + result, zip->cursor, delta );
289 result += delta;
290 zip->cursor += delta;
291 zip->pos += delta;
292
293 count -= delta;
294 if ( count == 0 )
295 break;
296
297 error = ft_lzw_file_fill_output( zip );
298 if ( error )
299 break;
300 }
301
302 Exit:
303 return result;
304 }
305
306
307 /***************************************************************************/
308 /***************************************************************************/
309 /***** *****/
310 /***** L Z W E M B E D D I N G S T R E A M *****/
311 /***** *****/
312 /***************************************************************************/
313 /***************************************************************************/
314
315 static void
316 ft_lzw_stream_close( FT_Stream stream )
317 {
318 FT_LZWFile zip = (FT_LZWFile)stream->descriptor.pointer;
319 FT_Memory memory = stream->memory;
320
321
322 if ( zip )
323 {
324 /* finalize lzw file descriptor */
325 ft_lzw_file_done( zip );
326
327 FT_FREE( zip );
328
329 stream->descriptor.pointer = NULL;
330 }
331 }
332
333
334 static FT_ULong
335 ft_lzw_stream_io( FT_Stream stream,
336 FT_ULong pos,
337 FT_Byte* buffer,
338 FT_ULong count )
339 {
340 FT_LZWFile zip = (FT_LZWFile)stream->descriptor.pointer;
341
342
343 return ft_lzw_file_io( zip, pos, buffer, count );
344 }
345
346
347 FT_EXPORT_DEF( FT_Error )
348 FT_Stream_OpenLZW( FT_Stream stream,
349 FT_Stream source )
350 {
351 FT_Error error;
352 FT_Memory memory = source->memory;
353 FT_LZWFile zip;
354
355
356 /*
357 * Check the header right now; this prevents allocation of a huge
358 * LZWFile object (400 KByte of heap memory) if not necessary.
359 *
360 * Did I mention that you should never use .Z compressed font
361 * files?
362 */
363 error = ft_lzw_check_header( source );
364 if ( error )
365 goto Exit;
366
367 FT_ZERO( stream );
368 stream->memory = memory;
369
370 if ( !FT_NEW( zip ) )
371 {
372 error = ft_lzw_file_init( zip, stream, source );
373 if ( error )
374 {
375 FT_FREE( zip );
376 goto Exit;
377 }
378
379 stream->descriptor.pointer = zip;
380 }
381
382 stream->size = 0x7FFFFFFFL; /* don't know the real size! */
383 stream->pos = 0;
384 stream->base = 0;
385 stream->read = ft_lzw_stream_io;
386 stream->close = ft_lzw_stream_close;
387
388 Exit:
389 return error;
390 }
391
392
393 #include "ftzopen.c"
394
395
396 #else /* !FT_CONFIG_OPTION_USE_LZW */
397
398
399 FT_EXPORT_DEF( FT_Error )
400 FT_Stream_OpenLZW( FT_Stream stream,
401 FT_Stream source )
402 {
403 FT_UNUSED( stream );
404 FT_UNUSED( source );
405
406 return LZW_Err_Unimplemented_Feature;
407 }
408
409
410 #endif /* !FT_CONFIG_OPTION_USE_LZW */
411
412
413 /* END */