1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#include	"sfdchdr.h"
23
24
25/*	Discipline to treat a contiguous segment of a stream as a stream
26**	in its own right. The hard part in all this is to allow multiple
27**	segments of the stream to be used as substreams at the same time.
28**
29**	Written by David G. Korn and Kiem-Phong Vo (03/18/1998)
30*/
31
32typedef struct _subfile_s
33{
34	Sfdisc_t	disc;	/* sfio discipline */
35	Sfio_t*		parent;	/* parent stream */
36	Sfoff_t		offset;	/* starting offset */
37	Sfoff_t		extent;	/* size wanted */
38	Sfoff_t		here;	/* current seek location */
39} Subfile_t;
40
41#if __STD_C
42static ssize_t streamio(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc, int type)
43#else
44static ssize_t streamio(f, buf, n, disc, type)
45Sfio_t*		f;
46Void_t*		buf;
47size_t		n;
48Sfdisc_t*	disc;
49int		type;
50#endif
51{
52	reg Subfile_t	*su;
53	reg Sfoff_t	here, parent;
54	reg ssize_t	io;
55
56	su = (Subfile_t*)disc;
57
58	/* read just what we need */
59	if(su->extent >= 0 && (ssize_t)n > (io = (ssize_t)(su->extent - su->here)) )
60		n = io;
61	if(n <= 0)
62		return n;
63
64	/* save current location in parent stream */
65	parent = sfsk(f,(Sfoff_t)0,SEEK_CUR,disc);
66
67	/* read data */
68	here = su->here + su->offset;
69	if(sfsk(f,here,SEEK_SET,disc) != here)
70		io = 0;
71	else
72	{	if(type == SF_WRITE)
73			io = sfwr(f,buf,n,disc);
74		else	io = sfrd(f,buf,n,disc);
75		if(io > 0)
76			su->here += io;
77	}
78
79	/* restore parent current position */
80	sfsk(f,parent,SEEK_SET,disc);
81
82	return io;
83}
84
85#if __STD_C
86static ssize_t streamwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
87#else
88static ssize_t streamwrite(f, buf, n, disc)
89Sfio_t*		f;
90Void_t*		buf;
91size_t		n;
92Sfdisc_t*	disc;
93#endif
94{
95	return streamio(f,(Void_t*)buf,n,disc,SF_WRITE);
96}
97
98#if __STD_C
99static ssize_t streamread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
100#else
101static ssize_t streamread(f, buf, n, disc)
102Sfio_t*		f;
103Void_t*		buf;
104size_t		n;
105Sfdisc_t*	disc;
106#endif
107{
108	return streamio(f,buf,n,disc,SF_READ);
109}
110
111#if __STD_C
112static Sfoff_t streamseek(Sfio_t* f, Sfoff_t pos, int type, Sfdisc_t* disc)
113#else
114static Sfoff_t streamseek(f, pos, type, disc)
115Sfio_t*		f;
116Sfoff_t		pos;
117int		type;
118Sfdisc_t*	disc;
119#endif
120{
121	reg Subfile_t*	su;
122	reg Sfoff_t	here, parent;
123
124	su = (Subfile_t*)disc;
125
126	switch(type)
127	{
128	case SEEK_SET:
129		here = 0;
130		break;
131	case SEEK_CUR:
132		here = su->here;
133		break;
134	case SEEK_END:
135		if(su->extent >= 0)
136			here = su->extent;
137		else
138		{	parent = sfsk(f,(Sfoff_t)0,SEEK_CUR,disc);
139			if((here = sfsk(f,(Sfoff_t)0,SEEK_END,disc)) < 0)
140				return -1;
141			else	here -= su->offset;
142			sfsk(f,parent,SEEK_SET,disc);
143		}
144		break;
145	default:
146		return -1;
147	}
148
149	pos += here;
150	if(pos < 0 || (su->extent >= 0 && pos >= su->extent))
151		return -1;
152
153	return (su->here = pos);
154}
155
156#if __STD_C
157static int streamexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
158#else
159static int streamexcept(f, type, data, disc)
160Sfio_t*		f;
161int		type;
162Void_t*		data;
163Sfdisc_t*	disc;
164#endif
165{
166	if(type == SF_FINAL || type == SF_DPOP)
167		free(disc);
168	return 0;
169}
170
171#if __STD_C
172Sfio_t* sfdcsubstream(Sfio_t* f, Sfio_t* parent, Sfoff_t offset, Sfoff_t extent)
173#else
174Sfio_t* sfdcsubstream(f, parent, offset, extent)
175Sfio_t*	f;	/* stream */
176Sfio_t*	parent;	/* parent stream */
177Sfoff_t	offset;	/* offset in f */
178Sfoff_t	extent;	/* desired size */
179#endif
180{
181	reg Sfio_t*	sp;
182	reg Subfile_t*	su;
183	reg Sfoff_t	here;
184
185	/* establish that we can seek to offset */
186	if((here = sfseek(parent,(Sfoff_t)0,SEEK_CUR)) < 0 || sfseek(parent,offset,SEEK_SET) < 0)
187		return 0;
188	else	sfseek(parent,here,SEEK_SET);
189	sfpurge(parent);
190
191	if (!(sp = f) && !(sp = sfnew(NIL(Sfio_t*), NIL(Void_t*), (size_t)SF_UNBOUND, dup(sffileno(parent)), parent->flags)))
192		return 0;
193
194	if(!(su = (Subfile_t*)malloc(sizeof(Subfile_t))))
195	{	if(sp != f)
196			sfclose(sp);
197		return 0;
198	}
199	memset(su, 0, sizeof(*su));
200
201	su->disc.readf = streamread;
202	su->disc.writef = streamwrite;
203	su->disc.seekf = streamseek;
204	su->disc.exceptf = streamexcept;
205	su->parent = parent;
206	su->offset = offset;
207	su->extent = extent;
208
209	if(sfdisc(sp, (Sfdisc_t*)su) != (Sfdisc_t*)su)
210	{	free(su);
211		if(sp != f)
212			sfclose(sp);
213		return 0;
214	}
215
216	return sp;
217}
218