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