1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1998-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 
22 /*
23  * sfio pzip discipline
24  */
25 
26 #include "pzlib.h"
27 
28 #include <sfdcbzip.h>
29 
30 #define GZ_MAGIC_1	0x1f		/* 1st gzip magic char		*/
31 #define GZ_MAGIC_2	0x8b		/* 2nd gzip magic char		*/
32 #define LZ_MAGIC_2	0x9d		/* 2nd lzw magic char		*/
33 
34 #define PZ_GZ_MAGOFF	10		/* compressed magic offset	*/
35 #define PZ_GZ_MAGIC_1	0x92		/* 1st compressed magic char	*/
36 #define PZ_GZ_MAGIC_2	0x17		/* 2nd compressed magic char	*/
37 
38 typedef struct
39 {
40 	Sfdisc_t	sfdisc;		/* sfio discipline		*/
41 	Pzdisc_t	disc;		/* pzip discipline		*/
42 	Pz_t*		pz;		/* pz handle			*/
43 	Sfio_t*		io;		/* real pzwrite stream		*/
44 } Sfpzip_t;
45 
46 /*
47  * pzip exception handler
48  * free on close
49  */
50 
51 static int
sfpzexcept(Sfio_t * sp,int op,void * val,Sfdisc_t * dp)52 sfpzexcept(Sfio_t* sp, int op, void* val, Sfdisc_t* dp)
53 {
54 	register Sfpzip_t*	pz = (Sfpzip_t*)dp;
55 	int			r;
56 
57 	NoP(sp);
58 	switch (op)
59 	{
60 	case SF_ATEXIT:
61 		sfdisc(sp, SF_POPDISC);
62 		return 0;
63 	case SF_CLOSING:
64 	case SF_DPOP:
65 	case SF_FINAL:
66 		if (pz->pz)
67 		{
68 			pz->pz->flags &= ~PZ_STREAM;
69 			r = pzclose(pz->pz);
70 			pz->pz = 0;
71 		}
72 		else
73 			r = 0;
74 		if (op != SF_CLOSING)
75 			free(dp);
76 		return r;
77 	case SF_DBUFFER:
78 		return 1;
79 	case SF_SYNC:
80 		return val ? 0 : pzsync(pz->pz);
81 	case SFPZ_HANDLE:
82 		return (*((Pz_t**)val) = pz->pz) ? 1 : -1;
83 	}
84 	return 0;
85 }
86 
87 /*
88  * sfio pzip discipline read
89  */
90 
91 static ssize_t
sfpzread(Sfio_t * fp,Void_t * buf,size_t size,Sfdisc_t * dp)92 sfpzread(Sfio_t* fp, Void_t* buf, size_t size, Sfdisc_t* dp)
93 {
94 	register Sfpzip_t*	pz = (Sfpzip_t*)dp;
95 
96 	return pzread(pz->pz, buf, size);
97 }
98 
99 /*
100  * sfio pzip discipline write
101  */
102 
103 static ssize_t
sfpzwrite(Sfio_t * fp,const Void_t * buf,size_t size,Sfdisc_t * dp)104 sfpzwrite(Sfio_t* fp, const Void_t* buf, size_t size, Sfdisc_t* dp)
105 {
106 	register Sfpzip_t*	pz = (Sfpzip_t*)dp;
107 
108 	return pzwrite(pz->pz, pz->io, buf, size);
109 }
110 
111 /*
112  * create and push the sfio pzip discipline
113  *
114  * (flags&PZ_STAT) return
115  *	>0	is a pzip file
116  *	 0	not a pzip file
117  *	<0	error
118  * otherwise flags have pzopen() semantics and return
119  *	>0	discipline pushed (one or more of { pzip gzip lzw })
120  *	 0	discipline not needed
121  *	<0	error
122  */
123 
124 int
sfdcpzip(Sfio_t * sp,const char * path,unsigned long flags,Pzdisc_t * disc)125 sfdcpzip(Sfio_t* sp, const char* path, unsigned long flags, Pzdisc_t* disc)
126 {
127 	Sfio_t*		io;
128 	Sfpzip_t*	pz;
129 	Pz_t*		oz;
130 
131 	if (flags & PZ_HANDLE)
132 	{
133 		oz = (Pz_t*)sp;
134 		sp = oz->io;
135 	}
136 	else
137 		oz = 0;
138 	if (sfset(sp, 0, 0) & SF_WRITE)
139 	{
140 		if (flags & PZ_STAT)
141 			return -1;
142 	}
143 	else if (!(flags & PZ_FORCE))
144 	{
145 		unsigned char*	s;
146 		int		r;
147 		int		m1;
148 		int		m2;
149 
150 		if (!(r = sfset(sp, 0, 0) & SF_SHARE))
151 			sfset(sp, SF_SHARE, 1);
152 		s = (unsigned char*)sfreserve(sp, PZ_GZ_MAGOFF + 2, 1);
153 		if (!r)
154 			sfset(sp, SF_SHARE, 0);
155 		if (!s)
156 			return -1;
157 		m1 = s[0];
158 		m2 = s[1];
159 		r = m1 == PZ_MAGIC_1 && m2 == PZ_MAGIC_2 && s[2] > 0 && s[3] < 10 ||
160 		    m1 == GZ_MAGIC_1 && m2 == GZ_MAGIC_2 &&
161 		    s[PZ_GZ_MAGOFF] == PZ_GZ_MAGIC_1 && s[PZ_GZ_MAGOFF+1] == PZ_GZ_MAGIC_2;
162 		sfread(sp, s, 0);
163 		if (flags & PZ_STAT)
164 			return r;
165 		if (!r)
166 		{
167 			if (!(flags & PZ_NOGZIP))
168 			{
169 				if (m1 == GZ_MAGIC_1)
170 				{
171 					if (m2 == GZ_MAGIC_2)
172 						r = sfdcgzip(sp, (flags & PZ_CRC) ? 0 : SFGZ_NOCRC);
173 					else if (m2 == LZ_MAGIC_2)
174 						r = sfdclzw(sp, 0);
175 				}
176 				else if (m1 == 'B' && m2 == 'Z' && s[2] == 'h' && s[3] >= '1' && s[3] <= '9')
177 					r = sfdcbzip(sp, 0);
178 			}
179 			return r;
180 		}
181 		sfsync(sp);
182 	}
183 	if (!(io = sfnew(NiL, NiL, SF_UNBOUND, sffileno(sp), (sfset(sp, 0, 0) & (SF_READ|SF_WRITE)))))
184 		return -1;
185 	if (!(pz = newof(0, Sfpzip_t, 1, 0)))
186 	{
187 		io->_file = -1;
188 		sfclose(io);
189 		return -1;
190 	}
191 	pz->disc.version = PZ_VERSION;
192 	flags &= ~(PZ_READ|PZ_WRITE|PZ_STAT|PZ_STREAM|PZ_INTERNAL);
193 	flags |= PZ_PUSHED|PZ_STREAM|((sfset(sp, 0, 0) & SF_READ) ? PZ_READ : PZ_WRITE);
194 	if (oz && (oz->flags & PZ_WRITE))
195 		flags |= PZ_DELAY;
196 	if (disc)
197 	{
198 		pz->disc.errorf = disc->errorf;
199 		pz->disc.window = disc->window;
200 		pz->disc.options = disc->options;
201 		pz->disc.partition = disc->partition;
202 		if (disc->splitf)
203 			flags |= PZ_ACCEPT;
204 	}
205 	if (!(pz->pz = pzopen(&pz->disc, (char*)io, flags)) || (sp->_file = open("/dev/null", 0)) < 0)
206 	{
207 		io->_file = -1;
208 		sfclose(io);
209 		free(pz);
210 		return -1;
211 	}
212 	if (path)
213 		pz->pz->path = path;
214 	pz->sfdisc.exceptf = sfpzexcept;
215 	if (flags & PZ_WRITE)
216 	{
217 		pz->sfdisc.writef = sfpzwrite;
218 		pz->io = io;
219 	}
220 	else
221 		pz->sfdisc.readf = sfpzread;
222 	sfset(sp, SF_SHARE|SF_PUBLIC, 0);
223 	if (sfdisc(sp, &pz->sfdisc) != &pz->sfdisc)
224 	{
225 		close(sp->_file);
226 		sp->_file = io->_file;
227 		sfseek(sp, sftell(io), SEEK_SET);
228 		io->_file = -1;
229 		pzclose(pz->pz);
230 		free(pz);
231 		return -1;
232 	}
233 	if (oz)
234 		oz->flags |= pz->pz->flags & PZ_INTERNAL;
235 	return 1;
236 }
237