xref: /plan9/sys/src/cmd/gs/src/zfilterx.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1995, 1996, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: zfilterx.c,v 1.4 2002/02/21 22:24:54 giles Exp $ */
18 /* Extended (non-standard) filter creation */
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "gsstruct.h"
23 #include "ialloc.h"
24 #include "idict.h"
25 #include "idparam.h"
26 #include "store.h"
27 #include "strimpl.h"
28 #include "sfilter.h"
29 #include "sbwbs.h"
30 #include "sbhc.h"
31 #include "sbtx.h"
32 #include "shcgen.h"
33 #include "smtf.h"
34 #include "ifilter.h"
35 
36 /* ------ Bounded Huffman code filters ------ */
37 
38 /* Common setup for encoding and decoding filters */
39 private int
bhc_setup(os_ptr op,stream_BHC_state * pbhcs)40 bhc_setup(os_ptr op, stream_BHC_state * pbhcs)
41 {
42     int code;
43     int num_counts;
44     int data[max_hc_length + 1 + 256 + max_zero_run + 1];
45     uint dsize;
46     int i;
47     uint num_values, accum;
48     ushort *counts;
49     ushort *values;
50 
51     check_type(*op, t_dictionary);
52     check_dict_read(*op);
53     if ((code = dict_bool_param(op, "FirstBitLowOrder", false,
54 				&pbhcs->FirstBitLowOrder)) < 0 ||
55 	(code = dict_int_param(op, "MaxCodeLength", 1, max_hc_length,
56 			       max_hc_length, &num_counts)) < 0 ||
57 	(code = dict_bool_param(op, "EndOfData", true,
58 				&pbhcs->EndOfData)) < 0 ||
59 	(code = dict_uint_param(op, "EncodeZeroRuns", 2, 256,
60 				256, &pbhcs->EncodeZeroRuns)) < 0 ||
61     /* Note: the code returned from the following call */
62     /* is actually the number of elements in the array. */
63 	(code = dict_int_array_param(op, "Tables", countof(data),
64 				     data)) <= 0
65 	)
66 	return (code < 0 ? code : gs_note_error(e_rangecheck));
67     dsize = code;
68     if (dsize <= num_counts + 2)
69 	return_error(e_rangecheck);
70     for (i = 0, num_values = 0, accum = 0; i <= num_counts;
71 	 i++, accum <<= 1
72 	) {
73 	int count = data[i];
74 
75 	if (count < 0)
76 	    return_error(e_rangecheck);
77 	num_values += count;
78 	accum += count;
79     }
80     if (dsize != num_counts + 1 + num_values ||
81 	accum != 1 << (num_counts + 1) ||
82 	pbhcs->EncodeZeroRuns >
83 	(pbhcs->EndOfData ? num_values - 1 : num_values)
84 	)
85 	return_error(e_rangecheck);
86     for (; i < num_counts + 1 + num_values; i++) {
87 	int value = data[i];
88 
89 	if (value < 0 || value >= num_values)
90 	    return_error(e_rangecheck);
91     }
92     pbhcs->definition.counts = counts =
93 	(ushort *) ialloc_byte_array(num_counts + 1, sizeof(ushort),
94 				     "bhc_setup(counts)");
95     pbhcs->definition.values = values =
96 	(ushort *) ialloc_byte_array(num_values, sizeof(ushort),
97 				     "bhc_setup(values)");
98     if (counts == 0 || values == 0) {
99 	ifree_object(values, "bhc_setup(values)");
100 	ifree_object(counts, "bhc_setup(counts)");
101 	return_error(e_VMerror);
102     }
103     for (i = 0; i <= num_counts; i++)
104 	counts[i] = data[i];
105     pbhcs->definition.counts = counts;
106     pbhcs->definition.num_counts = num_counts;
107     for (i = 0; i < num_values; i++)
108 	values[i] = data[i + num_counts + 1];
109     pbhcs->definition.values = values;
110     pbhcs->definition.num_values = num_values;
111     return 0;
112 }
113 
114 /* <target> <dict> BoundedHuffmanEncode/filter <file> */
115 private int
zBHCE(i_ctx_t * i_ctx_p)116 zBHCE(i_ctx_t *i_ctx_p)
117 {
118     os_ptr op = osp;
119     stream_BHCE_state bhcs;
120     int code = bhc_setup(op, (stream_BHC_state *)&bhcs);
121 
122     if (code < 0)
123 	return code;
124     return filter_write(op, 0, &s_BHCE_template, (stream_state *)&bhcs, 0);
125 }
126 
127 /* <source> <dict> BoundedHuffmanDecode/filter <file> */
128 private int
zBHCD(i_ctx_t * i_ctx_p)129 zBHCD(i_ctx_t *i_ctx_p)
130 {
131     os_ptr op = osp;
132     stream_BHCD_state bhcs;
133     int code = bhc_setup(op, (stream_BHC_state *)&bhcs);
134 
135     if (code < 0)
136 	return code;
137     return filter_read(i_ctx_p, 0, &s_BHCD_template, (stream_state *)&bhcs, 0);
138 }
139 
140 /* <array> <max_length> .computecodes <array> */
141 /* The first max_length+1 elements of the array will be filled in with */
142 /* the code counts; the remaining elements will be replaced with */
143 /* the code values.  This is the form needed for the Tables element of */
144 /* the dictionary parameter for the BoundedHuffman filters. */
145 private int
zcomputecodes(i_ctx_t * i_ctx_p)146 zcomputecodes(i_ctx_t *i_ctx_p)
147 {
148     os_ptr op = osp;
149     os_ptr op1 = op - 1;
150     uint asize;
151     hc_definition def;
152     ushort *data;
153     long *freqs;
154     int code = 0;
155 
156     check_type(*op, t_integer);
157     check_write_type(*op1, t_array);
158     asize = r_size(op1);
159     if (op->value.intval < 1 || op->value.intval > max_hc_length)
160 	return_error(e_rangecheck);
161     def.num_counts = op->value.intval;
162     if (asize < def.num_counts + 2)
163 	return_error(e_rangecheck);
164     def.num_values = asize - (def.num_counts + 1);
165     data = (ushort *) gs_alloc_byte_array(imemory, asize, sizeof(ushort),
166 					  "zcomputecodes");
167     freqs = (long *)gs_alloc_byte_array(imemory, def.num_values,
168 					sizeof(long),
169 					"zcomputecodes(freqs)");
170 
171     if (data == 0 || freqs == 0)
172 	code = gs_note_error(e_VMerror);
173     else {
174 	uint i;
175 
176 	def.counts = data;
177 	def.values = data + (def.num_counts + 1);
178 	for (i = 0; i < def.num_values; i++) {
179 	    const ref *pf = op1->value.const_refs + i + def.num_counts + 1;
180 
181 	    if (!r_has_type(pf, t_integer)) {
182 		code = gs_note_error(e_typecheck);
183 		break;
184 	    }
185 	    freqs[i] = pf->value.intval;
186 	}
187 	if (!code) {
188 	    code = hc_compute(&def, freqs, imemory);
189 	    if (code >= 0) {
190 		/* Copy back results. */
191 		for (i = 0; i < asize; i++)
192 		    make_int(op1->value.refs + i, data[i]);
193 	    }
194 	}
195     }
196     gs_free_object(imemory, freqs, "zcomputecodes(freqs)");
197     gs_free_object(imemory, data, "zcomputecodes");
198     if (code < 0)
199 	return code;
200     pop(1);
201     return code;
202 }
203 
204 /* ------ Burrows/Wheeler block sorting filters ------ */
205 
206 /* Common setup for encoding and decoding filters */
207 private int
bwbs_setup(os_ptr op,stream_BWBS_state * pbwbss)208 bwbs_setup(os_ptr op, stream_BWBS_state * pbwbss)
209 {
210     int code =
211 	dict_int_param(op, "BlockSize", 1, max_int / sizeof(int) - 10, 16384,
212 		       &pbwbss->BlockSize);
213 
214     if (code < 0)
215 	return code;
216     return 0;
217 }
218 
219 /* <target> <dict> BWBlockSortEncode/filter <file> */
220 private int
zBWBSE(i_ctx_t * i_ctx_p)221 zBWBSE(i_ctx_t *i_ctx_p)
222 {
223     os_ptr op = osp;
224     stream_BWBSE_state bwbss;
225     int code;
226 
227     check_type(*op, t_dictionary);
228     check_dict_read(*op);
229     code = bwbs_setup(op, (stream_BWBS_state *)&bwbss);
230     if (code < 0)
231 	return code;
232     return filter_write(op, 0, &s_BWBSE_template, (stream_state *)&bwbss, 0);
233 }
234 
235 /* <source> <dict> BWBlockSortDecode/filter <file> */
236 private int
zBWBSD(i_ctx_t * i_ctx_p)237 zBWBSD(i_ctx_t *i_ctx_p)
238 {
239     os_ptr op = osp;
240     stream_BWBSD_state bwbss;
241     int code = bwbs_setup(op, (stream_BWBS_state *)&bwbss);
242 
243     if (code < 0)
244 	return code;
245     return filter_read(i_ctx_p, 0, &s_BWBSD_template, (stream_state *)&bwbss, 0);
246 }
247 
248 /* ------ Byte translation filters ------ */
249 
250 /* Common setup */
251 private int
bt_setup(os_ptr op,stream_BT_state * pbts)252 bt_setup(os_ptr op, stream_BT_state * pbts)
253 {
254     check_read_type(*op, t_string);
255     if (r_size(op) != 256)
256 	return_error(e_rangecheck);
257     memcpy(pbts->table, op->value.const_bytes, 256);
258     return 0;
259 }
260 
261 /* <target> <table> ByteTranslateEncode/filter <file> */
262 /* <target> <table> <dict> ByteTranslateEncode/filter <file> */
263 private int
zBTE(i_ctx_t * i_ctx_p)264 zBTE(i_ctx_t *i_ctx_p)
265 {
266     os_ptr op = osp;
267     stream_BT_state bts;
268     int code = bt_setup(op, &bts);
269 
270     if (code < 0)
271 	return code;
272     return filter_write(op, 0, &s_BTE_template, (stream_state *)&bts, 0);
273 }
274 
275 /* <target> <table> ByteTranslateDecode/filter <file> */
276 /* <target> <table> <dict> ByteTranslateDecode/filter <file> */
277 private int
zBTD(i_ctx_t * i_ctx_p)278 zBTD(i_ctx_t *i_ctx_p)
279 {
280     os_ptr op = osp;
281     stream_BT_state bts;
282     int code = bt_setup(op, &bts);
283 
284     if (code < 0)
285 	return code;
286     return filter_read(i_ctx_p, 0, &s_BTD_template, (stream_state *)&bts, 0);
287 }
288 
289 /* ------ Move-to-front filters ------ */
290 
291 /* <target> MoveToFrontEncode/filter <file> */
292 /* <target> <dict> MoveToFrontEncode/filter <file> */
293 private int
zMTFE(i_ctx_t * i_ctx_p)294 zMTFE(i_ctx_t *i_ctx_p)
295 {
296     os_ptr op = osp;
297 
298     return filter_write_simple(op, &s_MTFE_template);
299 }
300 
301 /* <source> MoveToFrontDecode/filter <file> */
302 /* <source> <dict> MoveToFrontDecode/filter <file> */
303 private int
zMTFD(i_ctx_t * i_ctx_p)304 zMTFD(i_ctx_t *i_ctx_p)
305 {
306     os_ptr op = osp;
307 
308     return filter_read_simple(op, &s_MTFD_template);
309 }
310 
311 /* ================ Initialization procedure ================ */
312 
313 const op_def zfilterx_op_defs[] =
314 {
315     {"2.computecodes", zcomputecodes},	/* not a filter */
316     op_def_begin_filter(),
317 		/* Non-standard filters */
318     {"2BoundedHuffmanEncode", zBHCE},
319     {"2BoundedHuffmanDecode", zBHCD},
320     {"2BWBlockSortEncode", zBWBSE},
321     {"2BWBlockSortDecode", zBWBSD},
322     {"2ByteTranslateEncode", zBTE},
323     {"2ByteTranslateDecode", zBTD},
324     {"1MoveToFrontEncode", zMTFE},
325     {"1MoveToFrontDecode", zMTFD},
326     op_def_end(0)
327 };
328