xref: /plan9/sys/src/cmd/gs/src/sfilter1.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1993, 2000 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: sfilter1.c,v 1.8 2002/02/21 22:24:54 giles Exp $ */
18 /* Filters included in Level 1 systems: NullEncode/Decode, PFBDecode, */
19 /*   SubFileDecode. */
20 #include "stdio_.h"		/* includes std.h */
21 #include "memory_.h"
22 #include "strimpl.h"
23 #include "sfilter.h"
24 
25 /* ------ PFBDecode ------ */
26 
27 private_st_PFBD_state();
28 
29 /* Initialize the state */
30 private int
s_PFBD_init(stream_state * st)31 s_PFBD_init(stream_state * st)
32 {
33     stream_PFBD_state *const ss = (stream_PFBD_state *) st;
34 
35     ss->record_type = -1;
36     return 0;
37 }
38 
39 /* Process a buffer */
40 private int
s_PFBD_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)41 s_PFBD_process(stream_state * st, stream_cursor_read * pr,
42 	       stream_cursor_write * pw, bool last)
43 {
44     stream_PFBD_state *const ss = (stream_PFBD_state *) st;
45     register const byte *p = pr->ptr;
46     register byte *q = pw->ptr;
47     int rcount, wcount;
48     int c;
49     int status = 0;
50 
51 top:
52     rcount = pr->limit - p;
53     wcount = pw->limit - q;
54     switch (ss->record_type) {
55 	case -1:		/* new record */
56 	    if (rcount < 2)
57 		goto out;
58 	    if (p[1] != 0x80)
59 		goto err;
60 	    c = p[2];
61 	    switch (c) {
62 		case 1:
63 		case 2:
64 		    break;
65 		case 3:
66 		    status = EOFC;
67 		    p += 2;
68 		    goto out;
69 		default:
70 		    p += 2;
71 		    goto err;
72 	    }
73 	    if (rcount < 6)
74 		goto out;
75 	    ss->record_type = c;
76 	    ss->record_left = p[3] + ((uint) p[4] << 8) +
77 		((ulong) p[5] << 16) +
78 		((ulong) p[6] << 24);
79 	    p += 6;
80 	    goto top;
81 	case 1:		/* text data */
82 	    /* Translate \r to \n. */
83 	    {
84 		int count = (wcount < rcount ? (status = 1, wcount) : rcount);
85 
86 		if (count > ss->record_left)
87 		    count = ss->record_left,
88 			status = 0;
89 		ss->record_left -= count;
90 		for (; count != 0; count--) {
91 		    c = *++p;
92 		    *++q = (c == '\r' ? '\n' : c);
93 		}
94 	    }
95 	    break;
96 	case 2:		/* binary data */
97 	    if (ss->binary_to_hex) {
98 		/* Translate binary to hex. */
99 		int count;
100 		const char *const hex_digits = "0123456789abcdef";
101 
102 		wcount >>= 1;	/* 2 chars per input byte */
103 		count = (wcount < rcount ? (status = 1, wcount) : rcount);
104 		if (count > ss->record_left)
105 		    count = ss->record_left,
106 			status = 0;
107 		ss->record_left -= count;
108 		for (; count != 0; count--) {
109 		    c = *++p;
110 		    q[1] = hex_digits[c >> 4];
111 		    q[2] = hex_digits[c & 0xf];
112 		    q += 2;
113 		}
114 	    } else {		/* Just read binary data. */
115 		int count = (wcount < rcount ? (status = 1, wcount) : rcount);
116 
117 		if (count > ss->record_left)
118 		    count = ss->record_left,
119 			status = 0;
120 		ss->record_left -= count;
121 		memcpy(q + 1, p + 1, count);
122 		p += count;
123 		q += count;
124 	    }
125 	    break;
126     }
127     if (ss->record_left == 0) {
128 	ss->record_type = -1;
129 	goto top;
130     }
131 out:
132     pr->ptr = p;
133     pw->ptr = q;
134     return status;
135 err:
136     pr->ptr = p;
137     pw->ptr = q;
138     return ERRC;
139 }
140 
141 /* Stream template */
142 const stream_template s_PFBD_template = {
143     &st_PFBD_state, s_PFBD_init, s_PFBD_process, 6, 2
144 };
145 
146 /* ------ SubFileDecode ------ */
147 
148 private_st_SFD_state();
149 
150 /* Set default parameter values. */
151 private void
s_SFD_set_defaults(stream_state * st)152 s_SFD_set_defaults(stream_state * st)
153 {
154     stream_SFD_state *const ss = (stream_SFD_state *) st;
155 
156     ss->count = 0;
157     ss->eod.data = 0;
158     ss->eod.size = 0;
159     ss->skip_count = 0;
160 }
161 
162 /* Initialize the stream */
163 private int
s_SFD_init(stream_state * st)164 s_SFD_init(stream_state * st)
165 {
166     stream_SFD_state *const ss = (stream_SFD_state *) st;
167 
168     ss->match = 0;
169     ss->copy_count = 0;
170     ss->min_left = (ss->eod.size != 0);
171 
172     return 0;
173 }
174 
175 /* Refill the buffer */
176 private int
s_SFD_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)177 s_SFD_process(stream_state * st, stream_cursor_read * pr,
178 	      stream_cursor_write * pw, bool last)
179 {
180     stream_SFD_state *const ss = (stream_SFD_state *) st;
181     register const byte *p = pr->ptr;
182     register byte *q = pw->ptr;
183     const byte *rlimit = pr->limit;
184     byte *wlimit = pw->limit;
185     int status = 0;
186 
187     if (ss->eod.size == 0) {	/* Just read, with no EOD pattern. */
188 	int rcount = rlimit - p;
189 	int wcount = wlimit - q;
190 	int count;
191 
192 	if (rcount <= ss->skip_count) { /* skipping */
193 	    ss->skip_count -= rcount;
194 	    pr->ptr = rlimit;
195 	    return 0;
196 	} else if (ss->skip_count > 0) {
197 	    rcount -= ss->skip_count;
198 	    pr->ptr = p += ss->skip_count;
199 	    ss->skip_count = 0;
200 	}
201 	count = min(rcount, wcount);
202 	if (ss->count == 0)	/* no EOD limit */
203 	    return stream_move(pr, pw);
204 	else if (ss->count > count) {	/* not EOD yet */
205 	    ss->count -= count;
206 	    return stream_move(pr, pw);
207 	} else {		/* We're going to reach EOD. */
208 	    count = ss->count;
209 	    if (count > 0) {
210 		memcpy(q + 1, p + 1, count);
211 		pr->ptr = p + count;
212 		pw->ptr = q + count;
213 	    }
214 	    ss->count = -1;
215 	    return EOFC;
216 	}
217     } else {			/* Read looking for an EOD pattern. */
218 	const byte *pattern = ss->eod.data;
219 	uint match = ss->match;
220 
221 cp:
222 	/* Check whether we're still copying a partial match. */
223 	if (ss->copy_count) {
224 	    int count = min(wlimit - q, ss->copy_count);
225 
226 	    memcpy(q + 1, ss->eod.data + ss->copy_ptr, count);
227 	    ss->copy_count -= count;
228 	    ss->copy_ptr += count;
229 	    q += count;
230 	    if (ss->copy_count != 0) {	/* hit wlimit */
231 		status = 1;
232 		goto xit;
233 	    } else if (ss->count < 0) {
234 		status = EOFC;
235 		goto xit;
236 	    }
237 	}
238 	while (p < rlimit) {
239 	    int c = *++p;
240 
241 	    if (c == pattern[match]) {
242 		if (++match == ss->eod.size) {
243 		    if (ss->skip_count > 0) {
244 			q = pw->ptr; /* undo any writes */
245 			ss->skip_count--;
246 			match = 0;
247 			continue;
248 		    }
249 		    /*
250 		     * We use if/else rather than switch because the value
251 		     * is long, which is not supported as a switch value in
252 		     * pre-ANSI C.
253 		     */
254 		    if (ss->count <= 0) {
255 			status = EOFC;
256 			goto xit;
257 		    } else if (ss->count == 1) {
258 			ss->count = -1;
259 		    } else
260 			ss->count--;
261 		    ss->copy_ptr = 0;
262 		    ss->copy_count = match;
263 		    match = 0;
264 		    goto cp;
265 		}
266 		continue;
267 	    }
268 	    /*
269 	     * No match here, back up to find the longest one.
270 	     * This may be quadratic in string_size, but
271 	     * we don't expect this to be a real problem.
272 	     */
273 	    if (match > 0) {
274 		int end = match;
275 
276 		while (match > 0) {
277 		    match--;
278 		    if (!memcmp(pattern, pattern + end - match, match))
279 			break;
280 		}
281 		/*
282 		 * Copy the unmatched initial portion of
283 		 * the EOD string to the output.
284 		 */
285 		p--;
286 		ss->copy_ptr = 0;
287 		ss->copy_count = end - match;
288 		goto cp;
289 	    }
290 	    if (q == wlimit) {
291 		p--;
292 		status = 1;
293 		break;
294 	    }
295 	    *++q = c;
296 	}
297 xit:	pr->ptr = p;
298 	if (ss->skip_count <= 0)
299 	    pw->ptr = q;
300 	ss->match = match;
301     }
302     return status;
303 }
304 
305 /* Stream template */
306 const stream_template s_SFD_template = {
307     &st_SFD_state, s_SFD_init, s_SFD_process, 1, 1, 0, s_SFD_set_defaults
308 };
309