xref: /plan9-contrib/sys/src/cmd/gs/src/zfdecode.c (revision d46c239f8612929b7dbade67d0d071633df3a15d)
1 /* Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This file is part of AFPL Ghostscript.
4 
5   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
6   distributor accepts any responsibility for the consequences of using it, or
7   for whether it serves any particular purpose or works at all, unless he or
8   she says so in writing.  Refer to the Aladdin Free Public License (the
9   "License") for full details.
10 
11   Every copy of AFPL Ghostscript must include a copy of the License, normally
12   in a plain ASCII text file named PUBLIC.  The License grants you the right
13   to copy, modify and redistribute AFPL Ghostscript, but only under certain
14   conditions described in the License.  Among other things, the License
15   requires that the copyright notice and this notice be preserved on all
16   copies.
17 */
18 
19 /*$Id: zfdecode.c,v 1.3 2000/09/19 19:00:53 lpd Exp $ */
20 /* Additional decoding filter creation */
21 #include "memory_.h"
22 #include "ghost.h"
23 #include "oper.h"
24 #include "gsparam.h"
25 #include "gsstruct.h"
26 #include "ialloc.h"
27 #include "idict.h"
28 #include "idparam.h"
29 #include "ilevel.h"		/* for LL3 test */
30 #include "iparam.h"
31 #include "store.h"
32 #include "stream.h"		/* for setting is_temp */
33 #include "strimpl.h"
34 #include "sfilter.h"
35 #include "sa85x.h"
36 #include "scfx.h"
37 #include "scf.h"
38 #include "slzwx.h"
39 #include "spdiffx.h"
40 #include "spngpx.h"
41 #include "ifilter.h"
42 #include "ifilter2.h"
43 #include "ifrpred.h"
44 
45 /* ------ ASCII85 filters ------ */
46 
47 /* We include both encoding and decoding filters here, */
48 /* because it would be a nuisance to separate them. */
49 
50 /* <target> ASCII85Encode/filter <file> */
51 /* <target> <dict> ASCII85Encode/filter <file> */
52 private int
53 zA85E(i_ctx_t *i_ctx_p)
54 {
55     return filter_write_simple(i_ctx_p, &s_A85E_template);
56 }
57 
58 /* <source> ASCII85Decode/filter <file> */
59 /* <source> <dict> ASCII85Decode/filter <file> */
60 private int
61 zA85D(i_ctx_t *i_ctx_p)
62 {
63     return filter_read_simple(i_ctx_p, &s_A85D_template);
64 }
65 
66 /* ------ CCITTFaxDecode filter ------ */
67 
68 /* Common setup for encoding and decoding filters. */
69 extern stream_state_proc_put_params(s_CF_put_params, stream_CF_state);
70 int
71 zcf_setup(os_ptr op, stream_CF_state *pcfs, gs_ref_memory_t *imem)
72 {
73     dict_param_list list;
74     int code = dict_param_list_read(&list, op, NULL, false, imem);
75 
76     if (code < 0)
77 	return code;
78     s_CF_set_defaults_inline(pcfs);
79     code = s_CF_put_params((gs_param_list *)&list, pcfs);
80     iparam_list_release(&list);
81     return code;
82 }
83 
84 /* <source> <dict> CCITTFaxDecode/filter <file> */
85 /* <source> CCITTFaxDecode/filter <file> */
86 private int
87 zCFD(i_ctx_t *i_ctx_p)
88 {
89     os_ptr op = osp;
90     os_ptr dop;
91     stream_CFD_state cfs;
92     int code;
93 
94     if (r_has_type(op, t_dictionary)) {
95 	check_dict_read(*op);
96 	dop = op;
97     } else
98 	dop = 0;
99     code = zcf_setup(dop, (stream_CF_state *)&cfs, iimemory);
100     if (code < 0)
101 	return code;
102     return filter_read(i_ctx_p, 0, &s_CFD_template, (stream_state *)&cfs, 0);
103 }
104 
105 /* ------ Common setup for possibly pixel-oriented decoding filters ------ */
106 
107 int
108 filter_read_predictor(i_ctx_t *i_ctx_p, int npop,
109 		      const stream_template * template, stream_state * st)
110 {
111     os_ptr op = osp;
112     int predictor, code;
113     stream_PDiff_state pds;
114     stream_PNGP_state pps;
115 
116     if (r_has_type(op, t_dictionary)) {
117 	if ((code = dict_int_param(op, "Predictor", 0, 15, 1, &predictor)) < 0)
118 	    return code;
119 	switch (predictor) {
120 	    case 0:		/* identity */
121 		predictor = 1;
122 	    case 1:		/* identity */
123 		break;
124 	    case 2:		/* componentwise horizontal differencing */
125 		code = zpd_setup(op, &pds);
126 		break;
127 	    case 10:
128 	    case 11:
129 	    case 12:
130 	    case 13:
131 	    case 14:
132 	    case 15:
133 		/* PNG prediction */
134 		code = zpp_setup(op, &pps);
135 		break;
136 	    default:
137 		return_error(e_rangecheck);
138 	}
139 	if (code < 0)
140 	    return code;
141     } else
142 	predictor = 1;
143     if (predictor == 1)
144 	return filter_read(i_ctx_p, npop, template, st, 0);
145     {
146 	/* We need to cascade filters. */
147 	ref rsource, rdict;
148 	int code;
149 
150 	/* Save the operands, just in case. */
151 	ref_assign(&rsource, op - 1);
152 	ref_assign(&rdict, op);
153 	code = filter_read(i_ctx_p, 1, template, st, 0);
154 	if (code < 0)
155 	    return code;
156 	/* filter_read changed osp.... */
157 	op = osp;
158 	code =
159 	    (predictor == 2 ?
160 	 filter_read(i_ctx_p, 0, &s_PDiffD_template, (stream_state *) & pds, 0) :
161 	  filter_read(i_ctx_p, 0, &s_PNGPD_template, (stream_state *) & pps, 0));
162 	if (code < 0) {
163 	    /* Restore the operands.  Don't bother trying to clean up */
164 	    /* the first stream. */
165 	    osp = ++op;
166 	    ref_assign(op - 1, &rsource);
167 	    ref_assign(op, &rdict);
168 	    return code;
169 	}
170 	/*
171 	 * Mark the compression stream as temporary, and propagate
172 	 * CloseSource from it to the predictor stream.
173 	 */
174 	filter_mark_strm_temp(op, 2);
175 	return code;
176     }
177 }
178 
179 /* ------ Generalized LZW/GIF decoding filter ------ */
180 
181 /* Common setup for encoding and decoding filters. */
182 int
183 zlz_setup(os_ptr op, stream_LZW_state * plzs)
184 {
185     int code;
186     const ref *dop;
187 
188     if (r_has_type(op, t_dictionary)) {
189 	check_dict_read(*op);
190 	dop = op;
191     } else
192 	dop = 0;
193     if (   (code = dict_int_param(dop, "EarlyChange", 0, 1, 1,
194 				  &plzs->EarlyChange)) < 0 ||
195 	   /*
196 	    * The following are not PostScript standard, although
197 	    * LanguageLevel 3 provides the first two under different
198 	    * names.
199 	    */
200 	   (code = dict_int_param(dop, "InitialCodeLength", 2, 11, 8,
201 				  &plzs->InitialCodeLength)) < 0 ||
202 	   (code = dict_bool_param(dop, "FirstBitLowOrder", false,
203 				   &plzs->FirstBitLowOrder)) < 0 ||
204 	   (code = dict_bool_param(dop, "BlockData", false,
205 				   &plzs->BlockData)) < 0
206 	)
207 	return code;
208     return 0;
209 }
210 
211 /* <source> LZWDecode/filter <file> */
212 /* <source> <dict> LZWDecode/filter <file> */
213 private int
214 zLZWD(i_ctx_t *i_ctx_p)
215 {
216     os_ptr op = osp;
217     stream_LZW_state lzs;
218     int code = zlz_setup(op, &lzs);
219 
220     if (code < 0)
221 	return code;
222     if (LL3_ENABLED && r_has_type(op, t_dictionary)) {
223 	int unit_size;
224 
225 	if ((code = dict_bool_param(op, "LowBitFirst", lzs.FirstBitLowOrder,
226 				    &lzs.FirstBitLowOrder)) < 0 ||
227 	    (code = dict_int_param(op, "UnitSize", 3, 8, 8,
228 				   &unit_size)) < 0
229 	    )
230 	    return code;
231 	if (code == 0 /* UnitSize specified */ )
232 	    lzs.InitialCodeLength = unit_size + 1;
233     }
234     return filter_read_predictor(i_ctx_p, 0, &s_LZWD_template,
235 				 (stream_state *) & lzs);
236 }
237 
238 /* ------ Color differencing filters ------ */
239 
240 /* We include both encoding and decoding filters here, */
241 /* because it would be a nuisance to separate them. */
242 
243 /* Common setup for encoding and decoding filters. */
244 int
245 zpd_setup(os_ptr op, stream_PDiff_state * ppds)
246 {
247     int code, bpc;
248 
249     check_type(*op, t_dictionary);
250     check_dict_read(*op);
251     if ((code = dict_int_param(op, "Colors", 1, s_PDiff_max_Colors, 1,
252 			       &ppds->Colors)) < 0 ||
253 	(code = dict_int_param(op, "BitsPerComponent", 1, 8, 8,
254 			       &bpc)) < 0 ||
255 	(bpc & (bpc - 1)) != 0 ||
256 	(code = dict_int_param(op, "Columns", 1, max_int, 1,
257 			       &ppds->Columns)) < 0
258 	)
259 	return (code < 0 ? code : gs_note_error(e_rangecheck));
260     ppds->BitsPerComponent = bpc;
261     return 0;
262 }
263 
264 /* <target> <dict> PixelDifferenceEncode/filter <file> */
265 private int
266 zPDiffE(i_ctx_t *i_ctx_p)
267 {
268     os_ptr op = osp;
269     stream_PDiff_state pds;
270     int code = zpd_setup(op, &pds);
271 
272     if (code < 0)
273 	return code;
274     return filter_write(i_ctx_p, 0, &s_PDiffE_template, (stream_state *) & pds, 0);
275 }
276 
277 /* <source> <dict> PixelDifferenceDecode/filter <file> */
278 private int
279 zPDiffD(i_ctx_t *i_ctx_p)
280 {
281     os_ptr op = osp;
282     stream_PDiff_state pds;
283     int code = zpd_setup(op, &pds);
284 
285     if (code < 0)
286 	return code;
287     return filter_read(i_ctx_p, 0, &s_PDiffD_template, (stream_state *) & pds, 0);
288 }
289 
290 /* ------ PNG pixel predictor filters ------ */
291 
292 /* Common setup for encoding and decoding filters. */
293 int
294 zpp_setup(os_ptr op, stream_PNGP_state * ppps)
295 {
296     int code, bpc;
297 
298     check_type(*op, t_dictionary);
299     check_dict_read(*op);
300     if ((code = dict_int_param(op, "Colors", 1, 16, 1,
301 			       &ppps->Colors)) < 0 ||
302 	(code = dict_int_param(op, "BitsPerComponent", 1, 16, 8,
303 			       &bpc)) < 0 ||
304 	(bpc & (bpc - 1)) != 0 ||
305 	(code = dict_uint_param(op, "Columns", 1, max_uint, 1,
306 				&ppps->Columns)) < 0 ||
307 	(code = dict_int_param(op, "Predictor", 10, 15, 15,
308 			       &ppps->Predictor)) < 0
309 	)
310 	return (code < 0 ? code : gs_note_error(e_rangecheck));
311     ppps->BitsPerComponent = bpc;
312     return 0;
313 }
314 
315 /* <target> <dict> PNGPredictorEncode/filter <file> */
316 private int
317 zPNGPE(i_ctx_t *i_ctx_p)
318 {
319     os_ptr op = osp;
320     stream_PNGP_state pps;
321     int code = zpp_setup(op, &pps);
322 
323     if (code < 0)
324 	return code;
325     return filter_write(i_ctx_p, 0, &s_PNGPE_template, (stream_state *) & pps, 0);
326 }
327 
328 /* <source> <dict> PNGPredictorDecode/filter <file> */
329 private int
330 zPNGPD(i_ctx_t *i_ctx_p)
331 {
332     os_ptr op = osp;
333     stream_PNGP_state pps;
334     int code = zpp_setup(op, &pps);
335 
336     if (code < 0)
337 	return code;
338     return filter_read(i_ctx_p, 0, &s_PNGPD_template, (stream_state *) & pps, 0);
339 }
340 
341 /* ---------------- Initialization procedure ---------------- */
342 
343 const op_def zfdecode_op_defs[] = {
344     op_def_begin_filter(),
345     {"1ASCII85Encode", zA85E},
346     {"1ASCII85Decode", zA85D},
347     {"2CCITTFaxDecode", zCFD},
348     {"1LZWDecode", zLZWD},
349     {"2PixelDifferenceDecode", zPDiffD},
350     {"2PixelDifferenceEncode", zPDiffE},
351     {"2PNGPredictorDecode", zPNGPD},
352     {"2PNGPredictorEncode", zPNGPE},
353     op_def_end(0)
354 };
355