Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1989, 2000, 2001 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: stream.c,v 1.26 2004/10/07 05:18:34 ray Exp $ */
18
/* Stream package for Ghostscript interpreter */
19
#include "stdio_.h"		/* includes std.h */
20
#include "memory_.h"
21
#include "gdebug.h"
22
#include "gpcheck.h"
23
#include "stream.h"
24
#include "strimpl.h"
25
 
26
/* Forward declarations */
27
private int sreadbuf(stream *, stream_cursor_write *);
28
private int swritebuf(stream *, stream_cursor_read *, bool);
29
private void stream_compact(stream *, bool);
30
 
31
/* Structure types for allocating streams. */
32
public_st_stream();
33
public_st_stream_state();	/* default */
34
/* GC procedures */
35
private 
36
ENUM_PTRS_WITH(stream_enum_ptrs, stream *st) return 0;
37
case 0:
38
if (st->foreign)
39
    ENUM_RETURN(NULL);
40
else if (st->cbuf_string.data != 0)
41
    ENUM_RETURN_STRING_PTR(stream, cbuf_string);
42
else
43
    ENUM_RETURN(st->cbuf);
44
ENUM_PTR3(1, stream, strm, prev, next);
45
ENUM_PTR(4, stream, state);
46
case 5: return ENUM_CONST_STRING(&st->file_name);
47
ENUM_PTRS_END
48
private RELOC_PTRS_WITH(stream_reloc_ptrs, stream *st)
49
{
50
    byte *cbuf_old = st->cbuf;
51
 
52
    if (cbuf_old != 0 && !st->foreign) {
53
	long reloc;
54
 
55
	if (st->cbuf_string.data != 0) {
56
	    RELOC_STRING_VAR(st->cbuf_string);
57
	    st->cbuf = st->cbuf_string.data;
58
	} else
59
	    RELOC_VAR(st->cbuf);
60
	reloc = cbuf_old - st->cbuf;
61
	/* Relocate the other buffer pointers. */
62
	st->srptr -= reloc;
63
	st->srlimit -= reloc;	/* same as swptr */
64
	st->swlimit -= reloc;
65
    }
66
    RELOC_VAR(st->strm);
67
    RELOC_VAR(st->prev);
68
    RELOC_VAR(st->next);
69
    RELOC_VAR(st->state);
70
    RELOC_CONST_STRING_VAR(st->file_name);
71
}
72
RELOC_PTRS_END
73
/* Finalize a stream by closing it. */
74
/* We only do this for file streams, because other kinds of streams */
75
/* may attempt to free storage when closing. */
76
private void
77
stream_finalize(void *vptr)
78
{
79
    stream *const st = vptr;
80
 
81
    if_debug2('u', "[u]%s 0x%lx\n",
82
	      (!s_is_valid(st) ? "already closed:" :
83
	       st->is_temp ? "is_temp set:" :
84
	       st->file == 0 ? "not file:" :
85
	       "closing file:"), (ulong) st);
86
    if (s_is_valid(st) && !st->is_temp && st->file != 0) {
87
	/* Prevent any attempt to free the buffer. */
88
	st->cbuf = 0;
89
	st->cbuf_string.data = 0;
90
	sclose(st);		/* ignore errors */
91
    }
92
}
93
 
94
/* Dummy template for streams that don't have a separate state. */
95
private const stream_template s_no_template = {
96
    &st_stream_state, 0, 0, 1, 1, 0
97
};
98
 
99
/* ------ Generic procedures ------ */
100
 
101
/* Allocate a stream and initialize it minimally. */
102
void
103
s_init(stream *s, gs_memory_t * mem)
104
{
105
    s->memory = mem;
106
    s->report_error = s_no_report_error;
107
    s->min_left = 0;
108
    s->error_string[0] = 0;
109
    s->prev = s->next = 0;	/* clean for GC */
110
    s->file_name.data = 0;	/* ibid. */
111
    s->file_name.size = 0;	
112
    s->close_strm = false;	/* default */
113
    s->close_at_eod = true;	/* default */
114
}
115
stream *
116
s_alloc(gs_memory_t * mem, client_name_t cname)
117
{
118
    stream *s = gs_alloc_struct(mem, stream, &st_stream, cname);
119
 
120
    if_debug2('s', "[s]alloc(%s) = 0x%lx\n",
121
	      client_name_string(cname), (ulong) s);
122
    if (s == 0)
123
	return 0;
124
    s_init(s, mem);
125
    return s;
126
}
127
 
128
/* Allocate a stream state and initialize it minimally. */
129
void
130
s_init_state(stream_state *st, const stream_template *template,
131
	     gs_memory_t *mem)
132
{
133
    st->template = template;
134
    st->memory = mem;
135
    st->report_error = s_no_report_error;
136
    st->min_left = 0;
137
}
138
stream_state *
139
s_alloc_state(gs_memory_t * mem, gs_memory_type_ptr_t stype,
140
	      client_name_t cname)
141
{
142
    stream_state *st = gs_alloc_struct(mem, stream_state, stype, cname);
143
 
144
    if_debug3('s', "[s]alloc_state %s(%s) = 0x%lx\n",
145
	      client_name_string(cname),
146
	      client_name_string(stype->sname),
147
	      (ulong) st);
148
    if (st)
149
	s_init_state(st, NULL, mem);
150
    return st;
151
}
152
 
153
/* Standard stream initialization */
154
void
155
s_std_init(register stream * s, byte * ptr, uint len, const stream_procs * pp,
156
	   int modes)
157
{
158
    s->template = &s_no_template;
159
    s->cbuf = ptr;
160
    s->srptr = s->srlimit = s->swptr = ptr - 1;
161
    s->swlimit = ptr - 1 + len;
162
    s->end_status = 0;
163
    s->foreign = 0;
164
    s->modes = modes;
165
    s->cbuf_string.data = 0;
166
    s->position = 0;
167
    s->bsize = s->cbsize = len;
168
    s->strm = 0;		/* not a filter */
169
    s->is_temp = 0;
170
    s->procs = *pp;
171
    s->state = (stream_state *) s;	/* hack to avoid separate state */
172
    s->file = 0;
173
    s->file_name.data = 0;	/* in case stream is on stack */
174
    s->file_name.size = 0;
175
    if_debug4('s', "[s]init 0x%lx, buf=0x%lx, len=%u, modes=%d\n",
176
	      (ulong) s, (ulong) ptr, len, modes);
177
}
178
 
179
 
180
/* Set the file name of a stream, copying the name. */
181
/* Return <0 if the copy could not be allocated. */
182
int
183
ssetfilename(stream *s, const byte *data, uint size)
184
{
185
    byte *str =
186
	(s->file_name.data == 0 ?
187
	 gs_alloc_string(s->memory, size + 1, "ssetfilename") :
188
	 gs_resize_string(s->memory,
189
			  (byte *)s->file_name.data,	/* break const */
190
			  s->file_name.size,
191
			  size + 1, "ssetfilename"));
192
 
193
    if (str == 0)
194
	return -1;
195
    memcpy(str, data, size);
196
    str[size] = 0;
197
    s->file_name.data = str;
198
    s->file_name.size = size + 1;
199
    return 0;
200
}
201
 
202
/* Return the file name of a stream, if any. */
203
/* There is a guaranteed 0 byte after the string. */
204
int
205
sfilename(stream *s, gs_const_string *pfname)
206
{
207
    pfname->data = s->file_name.data;
208
    if (pfname->data == 0) {
209
	pfname->size = 0;
210
	return -1;
211
    }
212
    pfname->size = s->file_name.size - 1; /* omit terminator */
213
    return 0;
214
}
215
 
216
/* Implement a stream procedure as a no-op. */
217
int
218
s_std_null(stream * s)
219
{
220
    return 0;
221
}
222
 
223
/* Discard the contents of the buffer when reading. */
224
void
225
s_std_read_reset(stream * s)
226
{
227
    s->srptr = s->srlimit = s->cbuf - 1;
228
}
229
 
230
/* Discard the contents of the buffer when writing. */
231
void
232
s_std_write_reset(stream * s)
233
{
234
    s->swptr = s->cbuf - 1;
235
}
236
 
237
/* Flush data to end-of-file when reading. */
238
int
239
s_std_read_flush(stream * s)
240
{
241
    while (1) {
242
	s->srptr = s->srlimit = s->cbuf - 1;
243
	if (s->end_status)
244
	    break;
245
	s_process_read_buf(s);
246
    }
247
    return (s->end_status == EOFC ? 0 : s->end_status);
248
}
249
 
250
/* Flush buffered data when writing. */
251
int
252
s_std_write_flush(stream * s)
253
{
254
    return s_process_write_buf(s, false);
255
}
256
 
257
/* Indicate that the number of available input bytes is unknown. */
258
int
259
s_std_noavailable(stream * s, long *pl)
260
{
261
    *pl = -1;
262
    return 0;
263
}
264
 
265
/* Indicate an error when asked to seek. */
266
int
267
s_std_noseek(stream * s, long pos)
268
{
269
    return ERRC;
270
}
271
 
272
/* Standard stream closing. */
273
int
274
s_std_close(stream * s)
275
{
276
    return 0;
277
}
278
 
279
/* Standard stream mode switching. */
280
int
281
s_std_switch_mode(stream * s, bool writing)
282
{
283
    return ERRC;
284
}
285
 
286
/* Standard stream finalization.  Disable the stream. */
287
void
288
s_disable(register stream * s)
289
{
290
    s->cbuf = 0;
291
    s->bsize = 0;
292
    s->end_status = EOFC;
293
    s->modes = 0;
294
    s->cbuf_string.data = 0;
295
    /* The pointers in the next two statements should really be */
296
    /* initialized to ([const] byte *)0 - 1, but some very picky */
297
    /* compilers complain about this. */
298
    s->cursor.r.ptr = s->cursor.r.limit = 0;
299
    s->cursor.w.limit = 0;
300
    s->procs.close = s_std_null;
301
    /* Clear pointers for GC */
302
    s->strm = 0;
303
    s->state = (stream_state *) s;
304
    s->template = &s_no_template;
305
    /* Free the file name. */
306
    if (s->file_name.data) {
307
	gs_free_const_string(s->memory, s->file_name.data, s->file_name.size,
308
			     "s_disable(file_name)");
309
	s->file_name.data = 0;
310
	s->file_name.size = 0;
311
    }
312
    /****** SHOULD DO MORE THAN THIS ******/
313
    if_debug1('s', "[s]disable 0x%lx\n", (ulong) s);
314
}
315
 
316
/* Implement flushing for encoding filters. */
317
int
318
s_filter_write_flush(register stream * s)
319
{
320
    int status = s_process_write_buf(s, false);
321
 
322
    if (status != 0)
323
	return status;
324
    return sflush(s->strm);
325
}
326
 
327
/* Close a filter.  If this is an encoding filter, flush it first. */
328
/* If CloseTarget was specified (close_strm), then propagate the sclose */
329
int
330
s_filter_close(register stream * s)
331
{
332
    int status;
333
    bool close = s->close_strm;
334
    stream *stemp = s->strm;
335
 
336
    if (s_is_writing(s)) {
337
	int status = s_process_write_buf(s, true);
338
 
339
	if (status != 0 && status != EOFC)
340
	    return status;
341
        status = sflush(stemp);
342
	if (status != 0 && status != EOFC)
343
	    return status;
344
    }
345
    status = s_std_close(s);
346
    if (status != 0 && status != EOFC)
347
	return status;
348
    if (close && stemp != 0)
349
	return sclose(stemp);
350
    return status;
351
}
352
 
353
/* Disregard a stream error message. */
354
int
355
s_no_report_error(stream_state * st, const char *str)
356
{
357
    return 0;
358
}
359
 
360
/* Generic procedure structures for filters. */
361
 
362
const stream_procs s_filter_read_procs = {
363
    s_std_noavailable, s_std_noseek, s_std_read_reset,
364
    s_std_read_flush, s_filter_close
365
};
366
 
367
const stream_procs s_filter_write_procs = {
368
    s_std_noavailable, s_std_noseek, s_std_write_reset,
369
    s_filter_write_flush, s_filter_close
370
};
371
 
372
/* ------ Implementation-independent procedures ------ */
373
 
374
/* Store the amount of available data in a(n input) stream. */
375
int
376
savailable(stream * s, long *pl)
377
{
378
    return (*(s)->procs.available) (s, pl);
379
}
380
 
381
/* Return the current position of a stream. */
382
long
383
stell(stream * s)
384
{
385
    /*
386
     * The stream might have been closed, but the position
387
     * is still meaningful in this case.
388
     */
389
    const byte *ptr = (s_is_writing(s) ? s->swptr : s->srptr);
390
 
391
    return (ptr == 0 ? 0 : ptr + 1 - s->cbuf) + s->position;
392
}
393
 
394
/* Set the position of a stream. */
395
int
396
spseek(stream * s, long pos)
397
{
398
    if_debug3('s', "[s]seek 0x%lx to %ld, position was %ld\n",
399
	      (ulong) s, pos, stell(s));
400
    return (*(s)->procs.seek) (s, pos);
401
}
402
 
403
/* Switch a stream to read or write mode. */
404
/* Return 0 or ERRC. */
405
int
406
sswitch(register stream * s, bool writing)
407
{
408
    if (s->procs.switch_mode == 0)
409
	return ERRC;
410
    return (*s->procs.switch_mode) (s, writing);
411
}
412
 
413
/* Close a stream, disabling it if successful. */
414
/* (The stream may already be closed.) */
415
int
416
sclose(register stream * s)
417
{
418
    stream_state *st;
419
    int status = (*s->procs.close) (s);
420
 
421
    if (status < 0)
422
	return status;
423
    st = s->state;
424
    if (st != 0) {
425
	stream_proc_release((*release)) = st->template->release;
426
	if (release != 0)
427
	    (*release) (st);
428
	if (st != (stream_state *) s && st->memory != 0)
429
	    gs_free_object(st->memory, st, "s_std_close");
430
	s->state = (stream_state *) s;
431
    }
432
    s_disable(s);
433
    return status;
434
}
435
 
436
/*
437
 * Implement sgetc when the buffer may be empty.  If the buffer really is
438
 * empty, refill it and then read a byte.  Note that filters must read one
439
 * byte ahead, so that they can close immediately after the client reads the
440
 * last data byte if the next thing is an EOD.
441
 */
442
int
443
spgetcc(register stream * s, bool close_at_eod)
444
{
445
    int status, left;
446
    int min_left = sbuf_min_left(s);
447
 
448
    while (status = s->end_status,
449
	   left = s->srlimit - s->srptr,
450
	   left <= min_left && status >= 0
451
	)
452
	s_process_read_buf(s);
453
    if (left <= min_left &&
454
	(left == 0 || (status != EOFC && status != ERRC))
455
	) {
456
	/* Compact the stream so stell will return the right result. */
457
	stream_compact(s, true);
458
	if (status == EOFC && close_at_eod && s->close_at_eod) {
459
	    status = sclose(s);
460
	    if (status == 0)
461
		status = EOFC;
462
	    s->end_status = status;
463
	}
464
	return status;
465
    }
466
    return *++(s->srptr);
467
}
468
 
469
/* Implementing sputc when the buffer is full, */
470
/* by flushing the buffer and then writing the byte. */
471
int
472
spputc(register stream * s, byte b)
473
{
474
    for (;;) {
475
	if (s->end_status)
476
	    return s->end_status;
477
	if (!sendwp(s)) {
478
	    *++(s->swptr) = b;
479
	    return b;
480
	}
481
	s_process_write_buf(s, false);
482
    }
483
}
484
 
485
/* Push back a character onto a (read) stream. */
486
/* The character must be the same as the last one read. */
487
/* Return 0 on success, ERRC on failure. */
488
int
489
sungetc(register stream * s, byte c)
490
{
491
    if (!s_is_reading(s) || s->srptr < s->cbuf || *(s->srptr) != c)
492
	return ERRC;
493
    s->srptr--;
494
    return 0;
495
}
496
 
497
/* Get a string from a stream. */
498
/* Return 0 if the string was filled, or an exception status. */
499
int
500
sgets(stream * s, byte * buf, uint nmax, uint * pn)
501
{
502
    stream_cursor_write cw;
503
    int status = 0;
504
    int min_left = sbuf_min_left(s);
505
 
506
    cw.ptr = buf - 1;
507
    cw.limit = cw.ptr + nmax;
508
    while (cw.ptr < cw.limit) {
509
	int left;
510
 
511
	if ((left = s->srlimit - s->srptr) > min_left) {
512
	    s->srlimit -= min_left;
513
	    stream_move(&s->cursor.r, &cw);
514
	    s->srlimit += min_left;
515
	} else {
516
	    uint wanted = cw.limit - cw.ptr;
517
	    int c;
518
	    stream_state *st;
519
 
520
	    if (wanted >= s->bsize >> 2 &&
521
		(st = s->state) != 0 &&
522
		wanted >= st->template->min_out_size &&
523
		s->end_status == 0 &&
524
		left == 0
525
		) {
526
		byte *wptr = cw.ptr;
527
 
528
		cw.limit -= min_left;
529
		status = sreadbuf(s, &cw);
530
		cw.limit += min_left;
531
		/* Compact the stream so stell will return the right result. */
532
		stream_compact(s, true);
533
		/*
534
		 * We know the stream buffer is empty, so it's safe to
535
		 * update position.  However, we need to reset the read
536
		 * cursor to indicate that there is no data in the buffer.
537
		 */
538
		s->srptr = s->srlimit = s->cbuf - 1;
539
		s->position += cw.ptr - wptr;
540
		if (status != 1 || cw.ptr == cw.limit)
541
		    break;
542
	    }
543
	    c = spgetc(s);
544
	    if (c < 0) {
545
		status = c;
546
		break;
547
	    }
548
	    *++(cw.ptr) = c;
549
	}
550
    }
551
    *pn = cw.ptr + 1 - buf;
552
    return (status >= 0 ? 0 : status);
553
}
554
 
555
/* Write a string on a stream. */
556
/* Return 0 if the entire string was written, or an exception status. */
557
int
558
sputs(register stream * s, const byte * str, uint wlen, uint * pn)
559
{
560
    uint len = wlen;
561
    int status = s->end_status;
562
 
563
    if (status >= 0)
564
	while (len > 0) {
565
	    uint count = s->swlimit - s->swptr;
566
 
567
	    if (count > 0) {
568
		if (count > len)
569
		    count = len;
570
		memcpy(s->swptr + 1, str, count);
571
		s->swptr += count;
572
		str += count;
573
		len -= count;
574
	    } else {
575
		byte ch = *str++;
576
 
577
		status = sputc(s, ch);
578
		if (status < 0)
579
		    break;
580
		len--;
581
	    }
582
	}
583
    *pn = wlen - len;
584
    return (status >= 0 ? 0 : status);
585
}
586
 
587
/* Skip ahead a specified distance in a read stream. */
588
/* Return 0 or an exception status. */
589
/* Store the number of bytes skipped in *pskipped. */
590
int
591
spskip(register stream * s, long nskip, long *pskipped)
592
{
593
    long n = nskip;
594
    int min_left;
595
 
596
    if (nskip < 0 || !s_is_reading(s)) {
597
	*pskipped = 0;
598
	return ERRC;
599
    }
600
    if (s_can_seek(s)) {
601
	long pos = stell(s);
602
	int status = sseek(s, pos + n);
603
 
604
	*pskipped = stell(s) - pos;
605
	return status;
606
    }
607
    min_left = sbuf_min_left(s);
608
    while (sbufavailable(s) < n + min_left) {
609
	int status;
610
 
611
	n -= sbufavailable(s);
612
	s->srptr = s->srlimit;
613
	if (s->end_status) {
614
	    *pskipped = nskip - n;
615
	    return s->end_status;
616
	}
617
	status = sgetc(s);
618
	if (status < 0) {
619
	    *pskipped = nskip - n;
620
	    return status;
621
	}
622
	--n;
623
    }
624
    /* Note that if min_left > 0, n < 0 is possible; this is harmless. */
625
    s->srptr += n;
626
    *pskipped = nskip;
627
    return 0;
628
}
629
 
630
/* Read a line from a stream.  See srdline.h for the specification. */
631
int
632
sreadline(stream *s_in, stream *s_out, void *readline_data,
633
	  gs_const_string *prompt, gs_string * buf,
634
	  gs_memory_t * bufmem, uint * pcount, bool *pin_eol,
635
	  bool (*is_stdin)(const stream *))
636
{
637
    uint count = *pcount;
638
 
639
    /* Most systems define \n as 0xa and \r as 0xd; however, */
640
    /* OS-9 has \n == \r == 0xd and \l == 0xa.  The following */
641
    /* code works properly regardless of environment. */
642
#if '\n' == '\r'
643
#  define LF 0xa
644
#else
645
#  define LF '\n'
646
#endif
647
 
648
    if (count == 0 && s_out && prompt) {
649
	uint ignore_n;
650
	int ch = sputs(s_out, prompt->data, prompt->size, &ignore_n);
651
 
652
	if (ch < 0)
653
	    return ch;
654
    }
655
 
656
top:
657
    if (*pin_eol) {
658
	/*
659
	 * We're in the middle of checking for a two-character
660
	 * end-of-line sequence.  If we get an EOF here, stop, but
661
	 * don't signal EOF now; wait till the next read.
662
	 */
663
	int ch = spgetcc(s_in, false);
664
 
665
	if (ch == EOFC) {
666
	    *pin_eol = false;
667
	    return 0;
668
	} else if (ch < 0)
669
	    return ch;
670
	else if (ch != LF)
671
	    sputback(s_in);
672
	*pin_eol = false;
673
	return 0;
674
    }
675
    for (;;) {
676
	int ch = sgetc(s_in);
677
 
678
	if (ch < 0) {		/* EOF or exception */
679
	    *pcount = count;
680
	    return ch;
681
	}
682
	switch (ch) {
683
	    case '\r':
684
		{
685
#if '\n' == '\r'		/* OS-9 or similar */
686
		    if (!is_stdin(s_in))
687
#endif
688
		    {
689
			*pcount = count;
690
			*pin_eol = true;
691
			goto top;
692
		    }
693
		}
694
		/* falls through */
695
	    case LF:
696
#undef LF
697
		*pcount = count;
698
		return 0;
699
	}
700
	if (count >= buf->size) {	/* filled the string */
701
	    if (!bufmem) {
702
		sputback(s_in);
703
		*pcount = count;
704
		return 1;
705
	    }
706
	    {
707
		uint nsize = count + max(count, 20);
708
		byte *ndata = gs_resize_string(bufmem, buf->data, buf->size,
709
					       nsize, "sreadline(buffer)");
710
 
711
		if (ndata == 0)
712
		    return ERRC; /* no better choice */
713
		buf->data = ndata;
714
		buf->size = nsize;
715
	    }
716
	}
717
	buf->data[count++] = ch;
718
    }
719
    /*return 0; *//* not reached */
720
}
721
 
722
/* ------ Utilities ------ */
723
 
724
/*
725
 * Attempt to refill the buffer of a read stream.  Only call this if the
726
 * end_status is not EOFC, and if the buffer is (nearly) empty.
727
 */
728
int
729
s_process_read_buf(stream * s)
730
{
731
    int status;
732
 
733
    stream_compact(s, false);
734
    status = sreadbuf(s, &s->cursor.w);
735
    s->end_status = (status >= 0 ? 0 : status);
736
    return 0;
737
}
738
 
739
/*
740
 * Attempt to empty the buffer of a write stream.  Only call this if the
741
 * end_status is not EOFC.
742
 */
743
int
744
s_process_write_buf(stream * s, bool last)
745
{
746
    int status = swritebuf(s, &s->cursor.r, last);
747
 
748
    stream_compact(s, false);
749
    return (status >= 0 ? 0 : status);
750
}
751
 
752
/* Move forward or backward in a pipeline.  We temporarily reverse */
753
/* the direction of the pointers while doing this. */
754
/* (Cf the Deutsch-Schorr-Waite graph marking algorithm.) */
755
#define MOVE_BACK(curr, prev)\
756
  BEGIN\
757
    stream *back = prev->strm;\
758
    prev->strm = curr; curr = prev; prev = back;\
759
  END
760
#define MOVE_AHEAD(curr, prev)\
761
  BEGIN\
762
    stream *ahead = curr->strm;\
763
    curr->strm = prev; prev = curr; curr = ahead;\
764
  END
765
 
766
/*
767
 * Read from a stream pipeline.  Update end_status for all streams that were
768
 * actually touched.  Return the status from the outermost stream: this is
769
 * normally the same as s->end_status, except that if s->procs.process
770
 * returned 1, sreadbuf sets s->end_status to 0, but returns 1.
771
 */
772
private int
773
sreadbuf(stream * s, stream_cursor_write * pbuf)
774
{
775
    stream *prev = 0;
776
    stream *curr = s;
777
    int status;
778
 
779
    for (;;) {
780
	stream *strm;
781
	stream_cursor_write *pw;
782
	byte *oldpos;
783
 
784
	for (;;) {		/* Descend into the recursion. */
785
	    stream_cursor_read cr;
786
	    stream_cursor_read *pr;
787
	    int left;
788
	    bool eof;
789
 
790
	    strm = curr->strm;
791
	    if (strm == 0) {
792
		cr.ptr = 0, cr.limit = 0;
793
		pr = &cr;
794
		left = 0;
795
		eof = false;
796
	    } else {
797
		pr = &strm->cursor.r;
798
		left = sbuf_min_left(strm);
799
		left = min(left, pr->limit - pr->ptr);
800
		pr->limit -= left;
801
		eof = strm->end_status == EOFC;
802
	    }
803
	    pw = (prev == 0 ? pbuf : &curr->cursor.w);
804
	    if_debug4('s', "[s]read process 0x%lx, nr=%u, nw=%u, eof=%d\n",
805
		      (ulong) curr, (uint) (pr->limit - pr->ptr),
806
		      (uint) (pw->limit - pw->ptr), eof);
807
	    oldpos = pw->ptr;
808
	    status = (*curr->procs.process) (curr->state, pr, pw, eof);
809
	    pr->limit += left;
810
	    if_debug5('s', "[s]after read 0x%lx, nr=%u, nw=%u, status=%d, position=%d\n",
811
		      (ulong) curr, (uint) (pr->limit - pr->ptr),
812
		      (uint) (pw->limit - pw->ptr), status, s->position);
813
	    if (strm == 0 || status != 0)
814
		break;
815
	    if (strm->end_status < 0) {
816
		if (strm->end_status != EOFC || pw->ptr == oldpos)
817
		    status = strm->end_status;
818
		break;
819
	    }
820
	    MOVE_AHEAD(curr, prev);
821
	    stream_compact(curr, false);
822
	}
823
	/* If curr reached EOD and is a filter or file stream, close it. */
824
	/* (see PLRM 3rd, sec 3.8.2, p80) */
825
	if ((strm != 0 || curr->file) && status == EOFC &&
826
	    curr->cursor.r.ptr >= curr->cursor.r.limit &&
827
	    curr->close_at_eod
828
	    ) {
829
	    int cstat = sclose(curr);
830
 
831
	    if (cstat != 0)
832
		status = cstat;
833
	}
834
	/* Unwind from the recursion. */
835
	curr->end_status = (status >= 0 ? 0 : status);
836
	if (prev == 0)
837
	    return status;
838
	MOVE_BACK(curr, prev);
839
    }
840
}
841
 
842
/* Write to a pipeline. */
843
private int
844
swritebuf(stream * s, stream_cursor_read * pbuf, bool last)
845
{
846
    stream *prev = 0;
847
    stream *curr = s;
848
    int depth = 0;		/* # of non-temp streams before curr */
849
    int status;
850
 
851
    /*
852
     * The handling of EOFC is a little tricky.  There are two
853
     * invariants that keep it straight:
854
     *      - We only pass last = true to a stream if either it is
855
     * the first stream in the pipeline, or it is a temporary stream
856
     * below the first stream and the stream immediately above it has
857
     * end_status = EOFC.
858
     */
859
    for (;;) {
860
	for (;;) {
861
	    /* Move ahead in the pipeline. */
862
	    stream *strm = curr->strm;
863
	    stream_cursor_write cw;
864
	    stream_cursor_read *pr;
865
	    stream_cursor_write *pw;
866
 
867
	    /*
868
	     * We only want to set the last/end flag for
869
	     * the top-level stream and any temporary streams
870
	     * immediately below it.
871
	     */
872
	    bool end = last &&
873
		(prev == 0 ||
874
		 (depth <= 1 && prev->end_status == EOFC));
875
 
876
	    if (strm == 0)
877
		cw.ptr = 0, cw.limit = 0, pw = &cw;
878
	    else
879
		pw = &strm->cursor.w;
880
	    if (prev == 0)
881
		pr = pbuf;
882
	    else
883
		pr = &curr->cursor.r;
884
	    if_debug5('s',
885
		      "[s]write process 0x%lx(%s), nr=%u, nw=%u, end=%d\n",
886
		      (ulong)curr,
887
		      gs_struct_type_name(curr->state->template->stype),
888
		      (uint)(pr->limit - pr->ptr),
889
		      (uint)(pw->limit - pw->ptr), end);
890
	    status = curr->end_status;
891
	    if (status >= 0) {
892
		status = (*curr->procs.process)(curr->state, pr, pw, end);
893
		if_debug5('s',
894
			  "[s]after write 0x%lx, nr=%u, nw=%u, end=%d, status=%d\n",
895
			  (ulong) curr, (uint) (pr->limit - pr->ptr),
896
			  (uint) (pw->limit - pw->ptr), end, status);
897
		if (status == 0 && end)
898
		    status = EOFC;
899
		if (status == EOFC || status == ERRC)
900
		    curr->end_status = status;
901
	    }
902
	    if (strm == 0 || (status < 0 && status != EOFC))
903
		break;
904
	    if (status != 1) {
905
		/*
906
		 * Keep going if we are closing a filter with a sub-stream.
907
		 * We know status == 0 or EOFC.
908
		 */
909
		if (!end || !strm->is_temp)
910
		    break;
911
	    }
912
	    status = strm->end_status;
913
	    if (status < 0)
914
		break;
915
	    if (!curr->is_temp)
916
		++depth;
917
	    if_debug1('s', "[s]moving ahead, depth = %d\n", depth);
918
	    MOVE_AHEAD(curr, prev);
919
	    stream_compact(curr, false);
920
	}
921
	/* Move back in the pipeline. */
922
	curr->end_status = (status >= 0 ? 0 : status);
923
	if (status < 0 || prev == 0) {
924
	    /*
925
	     * All streams up to here were called with last = true
926
	     * and returned 0 or EOFC (so their end_status is now EOFC):
927
	     * finish unwinding and then return.  Change the status of
928
	     * the prior streams to ERRC if the new status is ERRC,
929
	     * otherwise leave it alone.
930
	     */
931
	    while (prev) {
932
		if_debug0('s', "[s]unwinding\n");
933
		MOVE_BACK(curr, prev);
934
		if (status >= 0)
935
		    curr->end_status = 0;
936
		else if (status == ERRC)
937
		    curr->end_status = ERRC;
938
	    }
939
	    return status;
940
	}
941
	MOVE_BACK(curr, prev);
942
	if (!curr->is_temp)
943
	    --depth;
944
	if_debug1('s', "[s]moving back, depth = %d\n", depth);
945
    }
946
}
947
 
948
/* Move as much data as possible from one buffer to another. */
949
/* Return 0 if the input became empty, 1 if the output became full. */
950
int
951
stream_move(stream_cursor_read * pr, stream_cursor_write * pw)
952
{
953
    uint rcount = pr->limit - pr->ptr;
954
    uint wcount = pw->limit - pw->ptr;
955
    uint count;
956
    int status;
957
 
958
    if (rcount <= wcount)
959
	count = rcount, status = 0;
960
    else
961
	count = wcount, status = 1;
962
    memmove(pw->ptr + 1, pr->ptr + 1, count);
963
    pr->ptr += count;
964
    pw->ptr += count;
965
    return status;
966
}
967
 
968
/* If possible, compact the information in a stream buffer to the bottom. */
969
private void
970
stream_compact(stream * s, bool always)
971
{
972
    if (s->cursor.r.ptr >= s->cbuf && (always || s->end_status >= 0)) {
973
	uint dist = s->cursor.r.ptr + 1 - s->cbuf;
974
 
975
	memmove(s->cbuf, s->cursor.r.ptr + 1,
976
		(uint) (s->cursor.r.limit - s->cursor.r.ptr));
977
	s->cursor.r.ptr = s->cbuf - 1;
978
	s->cursor.r.limit -= dist;	/* same as w.ptr */
979
	s->position += dist;
980
    }
981
}
982
 
983
/* ------ String streams ------ */
984
 
985
/* String stream procedures */
986
private int
987
    s_string_available(stream *, long *),
988
    s_string_read_seek(stream *, long),
989
    s_string_write_seek(stream *, long),
990
    s_string_read_process(stream_state *, stream_cursor_read *,
991
			  stream_cursor_write *, bool),
992
    s_string_write_process(stream_state *, stream_cursor_read *,
993
			   stream_cursor_write *, bool);
994
 
995
/* Initialize a stream for reading a string. */
996
void
997
sread_string(register stream *s, const byte *ptr, uint len)
998
{
999
    static const stream_procs p = {
1000
	 s_string_available, s_string_read_seek, s_std_read_reset,
1001
	 s_std_read_flush, s_std_null, s_string_read_process
1002
    };
1003
 
1004
    s_std_init(s, (byte *)ptr, len, &p, s_mode_read + s_mode_seek);
1005
    s->cbuf_string.data = (byte *)ptr;
1006
    s->cbuf_string.size = len;
1007
    s->end_status = EOFC;
1008
    s->srlimit = s->swlimit;
1009
}
1010
/* Initialize a reusable stream for reading a string. */
1011
private void
1012
s_string_reusable_reset(stream *s)
1013
{
1014
    s->srptr = s->cbuf - 1;	/* just reset to the beginning */
1015
    s->srlimit = s->srptr + s->bsize;  /* might have gotten reset */
1016
}
1017
private int
1018
s_string_reusable_flush(stream *s)
1019
{
1020
    s->srptr = s->srlimit = s->cbuf + s->bsize - 1;  /* just set to the end */
1021
    return 0;
1022
}
1023
void
1024
sread_string_reusable(stream *s, const byte *ptr, uint len)
1025
{
1026
    static const stream_procs p = {
1027
	 s_string_available, s_string_read_seek, s_string_reusable_reset,
1028
	 s_string_reusable_flush, s_std_null, s_string_read_process
1029
    };
1030
 
1031
    sread_string(s, ptr, len);
1032
    s->procs = p;
1033
    s->close_at_eod = false;
1034
}
1035
 
1036
/* Return the number of available bytes when reading from a string. */
1037
private int
1038
s_string_available(stream *s, long *pl)
1039
{
1040
    *pl = sbufavailable(s);
1041
    if (*pl == 0 && s->close_at_eod)	/* EOF */
1042
	*pl = -1;
1043
    return 0;
1044
}
1045
 
1046
/* Seek in a string being read.  Return 0 if OK, ERRC if not. */
1047
private int
1048
s_string_read_seek(register stream * s, long pos)
1049
{
1050
    if (pos < 0 || pos > s->bsize)
1051
	return ERRC;
1052
    s->srptr = s->cbuf + pos - 1;
1053
    /* We might be seeking after a reusable string reached EOF. */
1054
    s->srlimit = s->cbuf + s->bsize - 1;
1055
    /* 
1056
     * When the file reaches EOF,
1057
     * stream_compact sets s->position to its end. 
1058
     * Reset it now to allow stell to work properly
1059
     * after calls to this function.
1060
     * Note that if the riched EOF and this fuction
1061
     * was not called, stell still returns a wrong value.
1062
     */
1063
    s->position = 0;
1064
    return 0;
1065
}
1066
 
1067
/* Initialize a stream for writing a string. */
1068
void
1069
swrite_string(register stream * s, byte * ptr, uint len)
1070
{
1071
    static const stream_procs p = {
1072
	s_std_noavailable, s_string_write_seek, s_std_write_reset,
1073
	s_std_null, s_std_null, s_string_write_process
1074
    };
1075
 
1076
    s_std_init(s, ptr, len, &p, s_mode_write + s_mode_seek);
1077
    s->cbuf_string.data = ptr;
1078
    s->cbuf_string.size = len;
1079
}
1080
 
1081
/* Seek in a string being written.  Return 0 if OK, ERRC if not. */
1082
private int
1083
s_string_write_seek(register stream * s, long pos)
1084
{
1085
    if (pos < 0 || pos > s->bsize)
1086
	return ERRC;
1087
    s->swptr = s->cbuf + pos - 1;
1088
    return 0;
1089
}
1090
 
1091
/* Since we initialize the input buffer of a string read stream */
1092
/* to contain all of the data in the string, if we are ever asked */
1093
/* to refill the buffer, we should signal EOF. */
1094
private int
1095
s_string_read_process(stream_state * st, stream_cursor_read * ignore_pr,
1096
		      stream_cursor_write * pw, bool last)
1097
{
1098
    return EOFC;
1099
}
1100
/* Similarly, if we are ever asked to empty the buffer, it means that */
1101
/* there has been an overrun (unless we are closing the stream). */
1102
private int
1103
s_string_write_process(stream_state * st, stream_cursor_read * pr,
1104
		       stream_cursor_write * ignore_pw, bool last)
1105
{
1106
    return (last ? EOFC : ERRC);
1107
}
1108
 
1109
/* ------ Position-tracking stream ------ */
1110
 
1111
private int
1112
    s_write_position_process(stream_state *, stream_cursor_read *,
1113
			     stream_cursor_write *, bool);
1114
 
1115
/* Set up a write stream that just keeps track of the position. */
1116
void
1117
swrite_position_only(stream *s)
1118
{
1119
    static byte discard_buf[50];	/* size is arbitrary */
1120
 
1121
    swrite_string(s, discard_buf, sizeof(discard_buf));
1122
    s->procs.process = s_write_position_process;
1123
}
1124
 
1125
private int
1126
s_write_position_process(stream_state * st, stream_cursor_read * pr,
1127
			 stream_cursor_write * ignore_pw, bool last)
1128
{
1129
    pr->ptr = pr->limit;	/* discard data */
1130
    return 0;
1131
}
1132
 
1133
/* ------ Filter pipelines ------ */
1134
 
1135
/*
1136
 * Add a filter to an output pipeline.  The client must have allocated the
1137
 * stream state, if any, using the given allocator.  For s_init_filter, the
1138
 * client must have called s_init and s_init_state.
1139
 */
1140
int
1141
s_init_filter(stream *fs, stream_state *fss, byte *buf, uint bsize,
1142
	      stream *target)
1143
{
1144
    const stream_template *template = fss->template;
1145
 
1146
    if (bsize < template->min_in_size)
1147
	return ERRC;
1148
    s_std_init(fs, buf, bsize, &s_filter_write_procs, s_mode_write);
1149
    fs->procs.process = template->process;
1150
    fs->state = fss;
1151
    if (template->init) {
1152
	fs->end_status = (template->init)(fss);
1153
	if (fs->end_status < 0)
1154
	    return fs->end_status;
1155
    }
1156
    fs->strm = target;
1157
    return 0;
1158
}
1159
stream *
1160
s_add_filter(stream **ps, const stream_template *template,
1161
	     stream_state *ss, gs_memory_t *mem)
1162
{
1163
    stream *es;
1164
    stream_state *ess;
1165
    uint bsize = max(template->min_in_size, 256);	/* arbitrary */
1166
    byte *buf;
1167
 
1168
    /*
1169
     * Ensure enough buffering.  This may require adding an additional
1170
     * stream.
1171
     */
1172
    if (bsize > (*ps)->bsize && template->process != s_NullE_template.process) {
1173
	stream_template null_template;
1174
 
1175
	null_template = s_NullE_template;
1176
	null_template.min_in_size = bsize;
1177
	if (s_add_filter(ps, &null_template, NULL, mem) == 0)
1178
	    return 0;
1179
    }
1180
    es = s_alloc(mem, "s_add_filter(stream)");
1181
    buf = gs_alloc_bytes(mem, bsize, "s_add_filter(buf)");
1182
    if (es == 0 || buf == 0) {
1183
	gs_free_object(mem, buf, "s_add_filter(buf)");
1184
	gs_free_object(mem, es, "s_add_filter(stream)");
1185
	return 0;
1186
    }
1187
    ess = (ss == 0 ? (stream_state *)es : ss);
1188
    ess->template = template;
1189
    ess->memory = mem;
1190
    es->memory = mem;
1191
    if (s_init_filter(es, ess, buf, bsize, *ps) < 0)
1192
	return 0;
1193
    *ps = es;
1194
    return es;
1195
}
1196
 
1197
/*
1198
 * Close the filters in a pipeline, up to a given target stream, freeing
1199
 * their buffers and state structures.
1200
 */
1201
int
1202
s_close_filters(stream **ps, stream *target)
1203
{
1204
    while (*ps != target) {
1205
	stream *s = *ps;
1206
	gs_memory_t *mem = s->state->memory;
1207
	byte *sbuf = s->cbuf;
1208
	stream *next = s->strm;
1209
	int status = sclose(s);
1210
	stream_state *ss = s->state; /* sclose may set this to s */
1211
 
1212
	if (status < 0)
1213
	    return status;
1214
	if (mem) {
1215
	    gs_free_object(mem, sbuf, "s_close_filters(buf)");
1216
	    gs_free_object(mem, s, "s_close_filters(stream)");
1217
	    if (ss != (stream_state *)s)
1218
		gs_free_object(mem, ss, "s_close_filters(state)");
1219
	}
1220
	*ps = next;
1221
    }
1222
    return 0;
1223
}
1224
 
1225
/* ------ NullEncode/Decode ------ */
1226
 
1227
/* Process a buffer */
1228
private int
1229
s_Null_process(stream_state * st, stream_cursor_read * pr,
1230
	       stream_cursor_write * pw, bool last)
1231
{
1232
    return stream_move(pr, pw);
1233
}
1234
 
1235
/* Stream template */
1236
const stream_template s_NullE_template = {
1237
    &st_stream_state, NULL, s_Null_process, 1, 1
1238
};
1239
const stream_template s_NullD_template = {
1240
    &st_stream_state, NULL, s_Null_process, 1, 1
1241
};