Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
}