blob: f05177764d5614a8d0eb0fbf533b165be8233cc0 [file] [log] [blame]
David Turnerc1b6d082005-10-20 15:33:34 +00001/***************************************************************************/
2/* */
Werner Lemberg560d5fe2005-10-21 09:08:28 +00003/* ftlzw2.c */
David Turnerc1b6d082005-10-20 15:33:34 +00004/* */
Werner Lemberg560d5fe2005-10-21 09:08:28 +00005/* FreeType support for .Z compressed files (reimplementation). */
David Turnerc1b6d082005-10-20 15:33:34 +00006/* */
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/* */
Werner Lemberg7f049f42006-02-25 16:52:16 +000011/* Copyright 2004, 2005, 2006 by */
David Turnerc1b6d082005-10-20 15:33:34 +000012/* 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
David Turnerde271ab2006-02-25 14:53:02 +000029#include FT_LZW_H
David Turnerc1b6d082005-10-20 15:33:34 +000030#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
Werner Lemberg84cacd22005-10-23 19:25:41 +000065#define FT_LZW_BUFFER_SIZE 4096
David Turnerc1b6d082005-10-20 15:33:34 +000066
Werner Lemberg84cacd22005-10-23 19:25:41 +000067 typedef struct FT_LZWFileRec_
David Turnerc1b6d082005-10-20 15:33:34 +000068 {
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
Werner Lemberg84cacd22005-10-23 19:25:41 +000074 FT_Byte buffer[FT_LZW_BUFFER_SIZE]; /* output buffer */
75 FT_ULong pos; /* position in output */
David Turnerc1b6d082005-10-20 15:33:34 +000076 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
Werner Lemberg84cacd22005-10-23 19:25:41 +000094 /* head[0] && head[1] are the magic numbers */
David Turnerc1b6d082005-10-20 15:33:34 +000095 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
Werner Lemberg84cacd22005-10-23 19:25:41 +0000198
199 /* first, we skip what we can from the output buffer */
David Turnerc1b6d082005-10-20 15:33:34 +0000200 {
201 FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor );
202
Werner Lemberg84cacd22005-10-23 19:25:41 +0000203
David Turnerc1b6d082005-10-20 15:33:34 +0000204 if ( delta >= count )
205 delta = count;
206
207 zip->cursor += delta;
208 zip->pos += delta;
209
210 count -= delta;
211 }
212
Werner Lemberg84cacd22005-10-23 19:25:41 +0000213 /* next, we skip as many bytes remaining as possible */
David Turnerc1b6d082005-10-20 15:33:34 +0000214 while ( count > 0 )
215 {
216 FT_ULong delta = FT_LZW_BUFFER_SIZE;
217 FT_ULong numread;
218
Werner Lemberg84cacd22005-10-23 19:25:41 +0000219
David Turnerc1b6d082005-10-20 15:33:34 +0000220 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 {
Werner Lemberg84cacd22005-10-23 19:25:41 +0000252 /* 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 ) )
David Turnerc1b6d082005-10-20 15:33:34 +0000255 {
Werner Lemberg84cacd22005-10-23 19:25:41 +0000256 zip->cursor -= zip->pos - pos;
David Turnerc1b6d082005-10-20 15:33:34 +0000257 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 /*
Werner Lemberg84cacd22005-10-23 19:25:41 +0000357 * Check the header right now; this prevents allocation of a huge
David Turnerc1b6d082005-10-20 15:33:34 +0000358 * LZWFile object (400 KByte of heap memory) if not necessary.
359 *
360 * Did I mention that you should never use .Z compressed font
Werner Lemberg84cacd22005-10-23 19:25:41 +0000361 * files?
David Turnerc1b6d082005-10-20 15:33:34 +0000362 */
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
Werner Lemberg84cacd22005-10-23 19:25:41 +0000392
David Turnerc1b6d082005-10-20 15:33:34 +0000393#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 */