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