1 /* Copyright (C) 1991, 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: sfilter2.c,v 1.5 2002/02/21 22:24:54 giles Exp $ */
18 /* Simple Level 2 filters */
19 #include "stdio_.h" /* includes std.h */
20 #include "memory_.h"
21 #include "gdebug.h"
22 #include "strimpl.h"
23 #include "sa85x.h"
24 #include "sbtx.h"
25 #include "scanchar.h"
26
27 /* ------ ASCII85Encode ------ */
28
29 private_st_A85E_state();
30
31 /* Initialize the state */
32 private int
s_A85E_init(stream_state * st)33 s_A85E_init(stream_state * st)
34 {
35 stream_A85E_state *const ss = (stream_A85E_state *) st;
36
37 return s_A85E_init_inline(ss);
38 }
39
40 /* Process a buffer */
41 #define LINE_LIMIT 79 /* not 80, to satisfy Genoa FTS */
42 private int
s_A85E_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)43 s_A85E_process(stream_state * st, stream_cursor_read * pr,
44 stream_cursor_write * pw, bool last)
45 {
46 stream_A85E_state *const ss = (stream_A85E_state *) st;
47 register const byte *p = pr->ptr;
48 register byte *q = pw->ptr;
49 byte *qn = q + (LINE_LIMIT - ss->count); /* value of q before next EOL */
50 const byte *rlimit = pr->limit;
51 byte *wlimit = pw->limit;
52 int status = 0;
53 int prev = ss->last_char;
54 int count;
55
56 if_debug3('w', "[w85]initial ss->count = %d, rcount = %d, wcount = %d\n",
57 ss->count, (int)(rlimit - p), (int)(wlimit - q));
58 for (; (count = rlimit - p) >= 4; p += 4) {
59 ulong word =
60 ((ulong) (((uint) p[1] << 8) + p[2]) << 16) +
61 (((uint) p[3] << 8) + p[4]);
62
63 if (word == 0) {
64 if (q >= qn) {
65 if (wlimit - q < 2) {
66 status = 1;
67 break;
68 }
69 *++q = prev = '\n';
70 qn = q + LINE_LIMIT;
71 if_debug1('w', "[w85]EOL at %d bytes written\n",
72 (int)(q - pw->ptr));
73 } else {
74 if (q >= wlimit) {
75 status = 1;
76 break;
77 }
78 }
79 *++q = prev = 'z';
80 } else {
81 ulong v4 = word / 85; /* max 85^4 */
82 ulong v3 = v4 / 85; /* max 85^3 */
83 uint v2 = v3 / 85; /* max 85^2 */
84 uint v1 = v2 / 85; /* max 85 */
85
86 put: if (q + 5 > qn) {
87 if (q >= wlimit) {
88 status = 1;
89 break;
90 }
91 *++q = prev = '\n';
92 qn = q + LINE_LIMIT;
93 if_debug1('w', "[w85]EOL at %d bytes written\n",
94 (int)(q - pw->ptr));
95 goto put;
96 }
97 if (wlimit - q < 5) {
98 status = 1;
99 break;
100 }
101 q[1] = (byte) v1 + '!';
102 q[2] = (byte) (v2 - v1 * 85) + '!';
103 q[3] = (byte) ((uint) v3 - v2 * 85) + '!';
104 q[4] = (byte) ((uint) v4 - (uint) v3 * 85) + '!';
105 q[5] = (byte) ((uint) word - (uint) v4 * 85) + '!';
106 /*
107 * '%%' or '%!' at the beginning of the line will confuse some
108 * document managers: insert (an) EOL(s) if necessary to prevent
109 * this.
110 */
111 if (q[1] == '%') {
112 if (prev == '%') {
113 if (qn - q == LINE_LIMIT - 1) {
114 /* A line would begin with %%. */
115 *++q = prev = '\n';
116 qn = q + LINE_LIMIT;
117 if_debug1('w',
118 "[w85]EOL for %%%% at %d bytes written\n",
119 (int)(q - pw->ptr));
120 goto put;
121 }
122 } else if (prev == '\n' && (q[2] == '%' || q[2] == '!')) {
123 /*
124 * We may have to insert more than one EOL if
125 * there are more than two %s in a row.
126 */
127 int extra =
128 (q[2] == '!' ? 1 : /* else q[2] == '%' */
129 q[3] == '!' ? 2 :
130 q[3] != '%' ? 1 :
131 q[4] == '!' ? 3 :
132 q[4] != '%' ? 2 :
133 q[5] == '!' ? 4 :
134 q[5] != '%' ? 3 : 4);
135
136 if (wlimit - q < 5 + extra) {
137 status = 1;
138 break;
139 }
140 if_debug6('w', "[w]%c%c%c%c%c extra = %d\n",
141 q[1], q[2], q[3], q[4], q[5], extra);
142 switch (extra) {
143 case 4:
144 q[9] = q[5], q[8] = '\n';
145 goto e3;
146 case 3:
147 q[8] = q[5];
148 e3:q[7] = q[4], q[6] = '\n';
149 goto e2;
150 case 2:
151 q[7] = q[5], q[6] = q[4];
152 e2:q[5] = q[3], q[4] = '\n';
153 goto e1;
154 case 1:
155 q[6] = q[5], q[5] = q[4], q[4] = q[3];
156 e1:q[3] = q[2], q[2] = '\n';
157 }
158 if_debug1('w', "[w85]EOL at %d bytes written\n",
159 (int)(q + 2 * extra - pw->ptr));
160 qn = q + 2 * extra + LINE_LIMIT;
161 q += extra;
162 }
163 } else if (q[1] == '!' && prev == '%' &&
164 qn - q == LINE_LIMIT - 1
165 ) {
166 /* A line would begin with %!. */
167 *++q = prev = '\n';
168 qn = q + LINE_LIMIT;
169 if_debug1('w', "[w85]EOL for %%! at %d bytes written\n",
170 (int)(q - pw->ptr));
171 goto put;
172 }
173 prev = *(q += 5);
174 }
175 }
176 end:
177 ss->count = LINE_LIMIT - (qn - q);
178 /* Check for final partial word. */
179 if (last && status == 0 && count < 4) {
180 int nchars = (count == 0 ? 2 : count + 3);
181
182 if (wlimit - q < nchars)
183 status = 1;
184 else if (q + nchars > qn) {
185 *++q = '\n';
186 qn = q + LINE_LIMIT;
187 goto end;
188 }
189 else {
190 ulong word = 0;
191 ulong divisor = 85L * 85 * 85 * 85;
192
193 switch (count) {
194 case 3:
195 word += (uint) p[3] << 8;
196 case 2:
197 word += (ulong) p[2] << 16;
198 case 1:
199 word += (ulong) p[1] << 24;
200 p += count;
201 while (count-- >= 0) {
202 ulong v = word / divisor; /* actually only a byte */
203
204 *++q = (byte) v + '!';
205 word -= v * divisor;
206 divisor /= 85;
207 }
208 /*case 0: */
209 }
210 *++q = '~';
211 *++q = '>';
212 }
213 }
214 if_debug3('w', "[w85]final ss->count = %d, %d bytes read, %d written\n",
215 ss->count, (int)(p - pr->ptr), (int)(q - pw->ptr));
216 pr->ptr = p;
217 if (q > pw->ptr)
218 ss->last_char = *q;
219 pw->ptr = q;
220 return status;
221 }
222 #undef LINE_LIMIT
223
224 /* Stream template */
225 const stream_template s_A85E_template = {
226 &st_A85E_state, s_A85E_init, s_A85E_process, 4, 6
227 };
228
229 /* ------ ByteTranslateEncode/Decode ------ */
230
231 private_st_BT_state();
232
233 /* Process a buffer. Note that the same code serves for both streams. */
234 private int
s_BT_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)235 s_BT_process(stream_state * st, stream_cursor_read * pr,
236 stream_cursor_write * pw, bool last)
237 {
238 stream_BT_state *const ss = (stream_BT_state *) st;
239 const byte *p = pr->ptr;
240 byte *q = pw->ptr;
241 uint rcount = pr->limit - p;
242 uint wcount = pw->limit - q;
243 uint count;
244 int status;
245
246 if (rcount <= wcount)
247 count = rcount, status = 0;
248 else
249 count = wcount, status = 1;
250 while (count--)
251 *++q = ss->table[*++p];
252 pr->ptr = p;
253 pw->ptr = q;
254 return status;
255 }
256
257 /* Stream template */
258 const stream_template s_BTE_template = {
259 &st_BT_state, NULL, s_BT_process, 1, 1
260 };
261 const stream_template s_BTD_template = {
262 &st_BT_state, NULL, s_BT_process, 1, 1
263 };
264