1 /* Copyright (C) 1993, 1995, 1996, 1997, 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: sstring.c,v 1.5 2005/04/25 12:28:49 igor Exp $ */
18 /* String and hexstring streams (filters) */
19 #include "stdio_.h" /* includes std.h */
20 #include "memory_.h"
21 #include "string_.h"
22 #include "strimpl.h"
23 #include "sstring.h"
24 #include "scanchar.h"
25
26 /* ------ ASCIIHexEncode ------ */
27
28 private_st_AXE_state();
29
30 /* Initialize the state */
31 private int
s_AXE_init(stream_state * st)32 s_AXE_init(stream_state * st)
33 {
34 stream_AXE_state *const ss = (stream_AXE_state *) st;
35
36 return s_AXE_init_inline(ss);
37 }
38
39 /* Process a buffer */
40 private int
s_AXE_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)41 s_AXE_process(stream_state * st, stream_cursor_read * pr,
42 stream_cursor_write * pw, bool last)
43 {
44 stream_AXE_state *const ss = (stream_AXE_state *) st;
45 const byte *p = pr->ptr;
46 byte *q = pw->ptr;
47 int rcount = pr->limit - p;
48 int wcount = pw->limit - q;
49 int count;
50 int pos = ss->count;
51 const char *hex_digits = "0123456789ABCDEF";
52 int status = 0;
53
54 if (last && ss->EndOfData)
55 wcount--; /* leave room for '>' */
56 wcount -= (wcount + 64) / 65; /* leave room for \n */
57 wcount >>= 1; /* 2 chars per input byte */
58 count = (wcount < rcount ? (status = 1, wcount) : rcount);
59 while (--count >= 0) {
60 *++q = hex_digits[*++p >> 4];
61 *++q = hex_digits[*p & 0xf];
62 if (!(++pos & 31) && (count != 0 || !last))
63 *++q = '\n';
64 }
65 if (last && status == 0 && ss->EndOfData)
66 *++q = '>';
67 pr->ptr = p;
68 pw->ptr = q;
69 ss->count = pos & 31;
70 return status;
71 }
72
73 /* Stream template */
74 const stream_template s_AXE_template =
75 {&st_AXE_state, s_AXE_init, s_AXE_process, 1, 3
76 };
77
78 /* ------ ASCIIHexDecode ------ */
79
80 private_st_AXD_state();
81
82 /* Initialize the state */
83 private int
s_AXD_init(stream_state * st)84 s_AXD_init(stream_state * st)
85 {
86 stream_AXD_state *const ss = (stream_AXD_state *) st;
87
88 return s_AXD_init_inline(ss);
89 }
90
91 /* Process a buffer */
92 private int
s_AXD_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)93 s_AXD_process(stream_state * st, stream_cursor_read * pr,
94 stream_cursor_write * pw, bool last)
95 {
96 stream_AXD_state *const ss = (stream_AXD_state *) st;
97 int code = s_hex_process(pr, pw, &ss->odd, hex_ignore_whitespace);
98
99 switch (code) {
100 case 0:
101 if (ss->odd >= 0 && last) {
102 if (pw->ptr == pw->limit)
103 return 1;
104 *++(pw->ptr) = ss->odd << 4;
105 }
106 /* falls through */
107 case 1:
108 /* We still need to read ahead and check for EOD. */
109 for (; pr->ptr < pr->limit; pr->ptr++)
110 if (scan_char_decoder[pr->ptr[1]] != ctype_space) {
111 if (pr->ptr[1] == '>') {
112 pr->ptr++;
113 goto eod;
114 }
115 return 1;
116 }
117 return 0; /* still need to scan ahead */
118 default:
119 return code;
120 case ERRC:
121 ;
122 }
123 /*
124 * Check for EOD. ERRC implies at least one more character
125 * was read; we must unread it, since the caller might have
126 * invoked the filter with exactly the right count to read all
127 * the available data, and we might be reading past the end.
128 */
129 if (*pr->ptr != '>') { /* EOD */
130 --(pr->ptr);
131 return ERRC;
132 }
133 eod:if (ss->odd >= 0) {
134 if (pw->ptr == pw->limit)
135 return 1;
136 *++(pw->ptr) = ss->odd << 4;
137 }
138 return EOFC;
139 }
140
141 /* Stream template */
142 const stream_template s_AXD_template =
143 {&st_AXD_state, s_AXD_init, s_AXD_process, 2, 1
144 };
145
146 /* ------ PSStringEncode ------ */
147
148 /* Process a buffer */
149 private int
s_PSSE_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)150 s_PSSE_process(stream_state * st, stream_cursor_read * pr,
151 stream_cursor_write * pw, bool last)
152 {
153 const byte *p = pr->ptr;
154 const byte *rlimit = pr->limit;
155 byte *q = pw->ptr;
156 byte *wlimit = pw->limit;
157 int status = 0;
158
159 /* This doesn't have to be very efficient. */
160 while (p < rlimit) {
161 int c = *++p;
162
163 if (c < 32 || c >= 127) {
164 const char *pesc;
165 const char *const esc = "\n\r\t\b\f";
166
167 if (c < 32 && c != 0 && (pesc = strchr(esc, c)) != 0) {
168 if (wlimit - q < 2) {
169 --p;
170 status = 1;
171 break;
172 }
173 *++q = '\\';
174 *++q = "nrtbf"[pesc - esc];
175 continue;
176 }
177 if (wlimit - q < 4) {
178 --p;
179 status = 1;
180 break;
181 }
182 q[1] = '\\';
183 q[2] = (c >> 6) + '0';
184 q[3] = ((c >> 3) & 7) + '0';
185 q[4] = (c & 7) + '0';
186 q += 4;
187 continue;
188 } else if (c == '(' || c == ')' || c == '\\') {
189 if (wlimit - q < 2) {
190 --p;
191 status = 1;
192 break;
193 }
194 *++q = '\\';
195 } else {
196 if (q == wlimit) {
197 --p;
198 status = 1;
199 break;
200 }
201 }
202 *++q = c;
203 }
204 if (last && status == 0) {
205 if (q == wlimit)
206 status = 1;
207 else
208 *++q = ')';
209 }
210 pr->ptr = p;
211 pw->ptr = q;
212 return status;
213 }
214
215 /* Stream template */
216 const stream_template s_PSSE_template =
217 {&st_stream_state, NULL, s_PSSE_process, 1, 4
218 };
219
220 /* ------ PSStringDecode ------ */
221
222 private_st_PSSD_state();
223
224 /* Initialize the state */
225 int
s_PSSD_init(stream_state * st)226 s_PSSD_init(stream_state * st)
227 {
228 stream_PSSD_state *const ss = (stream_PSSD_state *) st;
229
230 ss->from_string = false;
231 return s_PSSD_partially_init_inline(ss);
232 }
233
234 /* Process a buffer */
235 private int
s_PSSD_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)236 s_PSSD_process(stream_state * st, stream_cursor_read * pr,
237 stream_cursor_write * pw, bool last)
238 {
239 stream_PSSD_state *const ss = (stream_PSSD_state *) st;
240 const byte *p = pr->ptr;
241 const byte *rlimit = pr->limit;
242 byte *q = pw->ptr;
243 byte *wlimit = pw->limit;
244 int status = 0;
245 int c;
246
247 #define check_p(n)\
248 if ( p == rlimit ) { p -= n; goto out; }
249 #define check_q(n)\
250 if ( q == wlimit ) { p -= n; status = 1; goto out; }
251 while (p < rlimit) {
252 c = *++p;
253 if (c == '\\' && !ss->from_string) {
254 check_p(1);
255 switch ((c = *++p)) {
256 case 'n':
257 c = '\n';
258 goto put;
259 case 'r':
260 c = '\r';
261 goto put;
262 case 't':
263 c = '\t';
264 goto put;
265 case 'b':
266 c = '\b';
267 goto put;
268 case 'f':
269 c = '\f';
270 goto put;
271 default: /* ignore the \ */
272 put:check_q(2);
273 *++q = c;
274 continue;
275 case char_CR: /* ignore, check for following \n */
276 check_p(2);
277 if (p[1] == char_EOL)
278 p++;
279 continue;
280 case char_EOL: /* ignore */
281 continue;
282 case '0':
283 case '1':
284 case '2':
285 case '3':
286 case '4':
287 case '5':
288 case '6':
289 case '7':
290 {
291 int d;
292
293 check_p(2);
294 d = p[1];
295 c -= '0';
296 if (d >= '0' && d <= '7') {
297 if (p + 1 == rlimit) {
298 p -= 2;
299 goto out;
300 }
301 check_q(2);
302 c = (c << 3) + d - '0';
303 d = p[2];
304 if (d >= '0' && d <= '7') {
305 c = (c << 3) + d - '0';
306 p += 2;
307 } else
308 p++;
309 } else
310 check_q(2);
311 *++q = c;
312 continue;
313 }
314 }
315 } else
316 switch (c) {
317 case '(':
318 check_q(1);
319 ss->depth++;
320 break;
321 case ')':
322 if (ss->depth == 0) {
323 status = EOFC;
324 goto out;
325 }
326 check_q(1);
327 ss->depth--;
328 break;
329 case char_CR: /* convert to \n */
330 check_p(1);
331 check_q(1);
332 if (p[1] == char_EOL)
333 p++;
334 *++q = '\n';
335 continue;
336 case char_EOL:
337 c = '\n';
338 default:
339 check_q(1);
340 break;
341 }
342 *++q = c;
343 }
344 #undef check_p
345 #undef check_q
346 out:pr->ptr = p;
347 pw->ptr = q;
348 if (last && status == 0 && p != rlimit)
349 status = ERRC;
350 return status;
351 }
352
353 /* Stream template */
354 const stream_template s_PSSD_template =
355 {&st_PSSD_state, s_PSSD_init, s_PSSD_process, 4, 1
356 };
357
358 /* ------ Utilities ------ */
359
360 /*
361 * Convert hex data to binary. Return 1 if we filled the string, 0 if
362 * we ran out of input data before filling the string, or ERRC on error.
363 * The caller must set *odd_digit to -1 before the first call;
364 * after each call, if an odd number of hex digits has been read (total),
365 * *odd_digit is the odd digit value, otherwise *odd_digit = -1.
366 * See strimpl.h for the definition of syntax.
367 */
368 int
s_hex_process(stream_cursor_read * pr,stream_cursor_write * pw,int * odd_digit,hex_syntax syntax)369 s_hex_process(stream_cursor_read * pr, stream_cursor_write * pw,
370 int *odd_digit, hex_syntax syntax)
371 {
372 const byte *p = pr->ptr;
373 const byte *rlimit = pr->limit;
374 byte *q = pw->ptr;
375 byte *wlimit = pw->limit;
376 byte *q0 = q;
377 byte val1 = (byte) * odd_digit;
378 byte val2;
379 uint rcount;
380 byte *flimit;
381 const byte *const decoder = scan_char_decoder;
382 int code = 0;
383
384 if (q >= wlimit)
385 return 1;
386 if (val1 <= 0xf)
387 goto d2;
388 d1:if ((rcount = (rlimit - p) >> 1) == 0)
389 goto x1;
390 /* Set up a fast end-of-loop check, so we don't have to test */
391 /* both p and q against their respective limits. */
392 flimit = (rcount < wlimit - q ? q + rcount : wlimit);
393 f1:if ((val1 = decoder[p[1]]) <= 0xf &&
394 (val2 = decoder[p[2]]) <= 0xf
395 ) {
396 p += 2;
397 *++q = (val1 << 4) + val2;
398 if (q < flimit)
399 goto f1;
400 if (q >= wlimit)
401 goto px;
402 }
403 x1:if (p >= rlimit)
404 goto end1;
405 if ((val1 = decoder[*++p]) > 0xf) {
406 if (val1 == ctype_space) {
407 switch (syntax) {
408 case hex_ignore_whitespace:
409 goto x1;
410 case hex_ignore_leading_whitespace:
411 if (q == q0 && *odd_digit < 0)
412 goto x1;
413 --p;
414 code = 1;
415 goto end1;
416 case hex_ignore_garbage:
417 goto x1;
418 }
419 } else if (syntax == hex_ignore_garbage)
420 goto x1;
421 code = ERRC;
422 goto end1;
423 }
424 d2:if (p >= rlimit) {
425 *odd_digit = val1;
426 goto ended;
427 }
428 if ((val2 = decoder[*++p]) > 0xf) {
429 if (val2 == ctype_space)
430 switch (syntax) {
431 case hex_ignore_whitespace:
432 goto d2;
433 case hex_ignore_leading_whitespace:
434 if (q == q0)
435 goto d2;
436 --p;
437 *odd_digit = val1;
438 code = 1;
439 goto ended;
440 case hex_ignore_garbage: /* pacify compilers */
441 ;
442 }
443 if (syntax == hex_ignore_garbage)
444 goto d2;
445 *odd_digit = val1;
446 code = ERRC;
447 goto ended;
448 }
449 *++q = (val1 << 4) + val2;
450 if (q < wlimit)
451 goto d1;
452 px:code = 1;
453 end1:*odd_digit = -1;
454 ended:pr->ptr = p;
455 pw->ptr = q;
456 return code;
457 }
458