1 /***********************************************************************
2 * *
3 * This software is part of the zlib package *
4 * Copyright (c) 1995-2009 Jean-loup Gailly and Mark Adler *
5 * *
6 * This software is provided 'as-is', without any express or implied *
7 * warranty. In no event will the authors be held liable for any *
8 * damages arising from the use of this software. *
9 * *
10 * Permission is granted to anyone to use this software for any *
11 * purpose, including commercial applications, and to alter it and *
12 * redistribute it freely, subject to the following restrictions: *
13 * *
14 * 1. The origin of this software must not be misrepresented; *
15 * you must not claim that you wrote the original software. If *
16 * you use this software in a product, an acknowledgment in the *
17 * product documentation would be appreciated but is not *
18 * required. *
19 * *
20 * 2. Altered source versions must be plainly marked as such, *
21 * and must not be misrepresented as being the original *
22 * software. *
23 * *
24 * 3. This notice may not be removed or altered from any source *
25 * distribution. *
26 * *
27 * This software is provided "as-is", without any express or implied *
28 * warranty. In no event will the authors be held liable for any damages*
29 * arising from the use of this software. *
30 * *
31 * Permission is granted to anyone to use this software for any purpose,*
32 * including commercial applications, and to alter it and redistribute i*
33 * freely, subject to the following restrictions: *
34 * *
35 * 1. The origin of this software must not be misrepresented; you must n*
36 * claim that you wrote the original software. If you use this softwa*
37 * in a product, an acknowledgment in the product documentation would*
38 * be appreciated but is not required. *
39 * *
40 * 2. Altered source versions must be plainly marked as such, and must n*
41 * be misrepresented as being the original software. *
42 * *
43 * 3. This notice may not be removed or altered from any source *
44 * distribution. *
45 * *
46 * Jean-loup Gailly *
47 * Mark Adler *
48 * *
49 ***********************************************************************/
50 #pragma prototyped
51
52 /*
53 * sfio gzip discipline
54 *
55 * handles { gzip compress vczip } on input
56 * handles { gzip compress } on output
57 */
58
59 #include <sfio_t.h>
60 #include <ast.h>
61 #include <zlib.h>
62 #include <sfdcgzip.h>
63
64 #ifdef z_off64_t
65 #undef z_off_t
66 #define z_off_t z_off64_t
67 #undef gzsync
68 #define gzsync gzsync64
69 #endif
70
71 typedef struct
72 {
73 Sfdisc_t disc; /* sfio discipline */
74 gzFile* gz; /* gz handle */
75 Sfio_t* op; /* original stream */
76 } Sfgzip_t;
77
78 /*
79 * gzip exception handler
80 * free on close
81 */
82
83 static int
sfgzexcept(Sfio_t * sp,int op,void * val,Sfdisc_t * dp)84 sfgzexcept(Sfio_t* sp, int op, void* val, Sfdisc_t* dp)
85 {
86 register Sfgzip_t* gz = (Sfgzip_t*)dp;
87 int f;
88 int r;
89
90 NoP(sp);
91 #if 0
92 {
93 static char aha[] = "AHA sfdcgzip event 0\n";
94 static int init;
95
96 if (!init)
97 init = getenv("SFGZ_DEBUG") ? 1 : -1;
98 if (init > 0)
99 {
100 aha[sizeof(aha) - 3] = '0' + op;
101 write(2, aha, sizeof(aha) - 1);
102 }
103 }
104 #endif
105 switch (op)
106 {
107 case SF_ATEXIT:
108 sfdisc(sp, SF_POPDISC);
109 return 0;
110 case SF_CLOSING:
111 case SF_DPOP:
112 case SF_FINAL:
113 if (gz->gz)
114 {
115 SFDCNEXT(sp, f);
116 if (r = gzclose(gz->gz) ? -1 : 0)
117 sp->_flags |= SF_ERROR;
118 gz->gz = 0;
119 SFDCPREV(sp, f);
120 }
121 else
122 r = 0;
123 if (gz->op)
124 {
125 sfclose(gz->op);
126 gz->op = 0;
127 }
128 if (op != SF_CLOSING)
129 free(dp);
130 return r;
131 case SF_DBUFFER:
132 return 1;
133 case SF_SYNC:
134 if (!val && gzsync(gz->gz, (z_off_t)(-1)) < 0)
135 sp->_flags |= SF_ERROR;
136 return 0;
137 case SFGZ_HANDLE:
138 return (*((gzFile**)val) = gz->gz) ? 1 : -1;
139 case SFGZ_GETPOS:
140 return (*((Sfoff_t*)val) = gzsync(gz->gz, (z_off_t)(-1))) < 0 ? -1 : 0;
141 case SFGZ_SETPOS:
142 return gzsync(gz->gz, (z_off_t)(*((Sfoff_t*)val))) < 0 ? -1 : 0;
143 }
144 return 0;
145 }
146
147 /*
148 * sfio gzip discipline seek
149 */
150
151 static Sfoff_t
sfgzseek(Sfio_t * fp,Sfoff_t off,int op,Sfdisc_t * dp)152 sfgzseek(Sfio_t* fp, Sfoff_t off, int op, Sfdisc_t* dp)
153 {
154 return sfsk(fp, off, op, dp);
155 }
156
157 /*
158 * sfio gzip discipline read
159 */
160
161 static ssize_t
sfgzread(Sfio_t * fp,Void_t * buf,size_t size,Sfdisc_t * dp)162 sfgzread(Sfio_t* fp, Void_t* buf, size_t size, Sfdisc_t* dp)
163 {
164 register Sfgzip_t* gz = (Sfgzip_t*)dp;
165
166 return gzread(gz->gz, buf, size);
167 }
168
169 /*
170 * sfio gzip discipline write
171 */
172
173 static ssize_t
sfgzwrite(Sfio_t * fp,const Void_t * buf,size_t size,Sfdisc_t * dp)174 sfgzwrite(Sfio_t* fp, const Void_t* buf, size_t size, Sfdisc_t* dp)
175 {
176 register Sfgzip_t* gz = (Sfgzip_t*)dp;
177
178 return gzwrite(gz->gz, (void*)buf, size);
179 }
180
181 /*
182 * create and push the sfio gzip discipline
183 *
184 * (flags&SFGZ_VERIFY) return
185 * >0 is a { g:gzip c:compress v:vczip } file
186 * 0 not a { gzip compress vczip } file
187 * <0 error
188 * otherwise return
189 * >0 discipline pushed { g:gzip c:compress v:vczip }
190 * 0 discipline not needed
191 * <0 error
192 */
193
194 #undef PRIVATE
195 #define PRIVATE 0
196
197 int
sfdcgzip(Sfio_t * sp,int flags)198 sfdcgzip(Sfio_t* sp, int flags)
199 {
200 char* m;
201 Sfgzip_t* gz;
202 int fd;
203 int rd;
204 size_t z;
205 char mode[10];
206
207 rd = sfset(sp, 0, 0) & SF_READ;
208 if (rd)
209 {
210 register unsigned char* s;
211 register int n;
212 register int r;
213
214 /*
215 * peek the first 4 bytes to verify the magic
216 *
217 * 0x1f8b.... sfdcgzip gzip
218 * 0x1f9d.... sfdclzw compress
219 * 0xd6c3c4d8 sfpopen vcunzip
220 */
221
222 #if PRIVATE
223 if (!(n = sfset(sp, 0, 0) & SF_SHARE))
224 sfset(sp, SF_SHARE, 1);
225 #endif
226 s = (unsigned char*)sfreserve(sp, 4, SF_LOCKR);
227 #if PRIVATE
228 if (!n)
229 sfset(sp, SF_SHARE, 0);
230 #endif
231 if (!s)
232 return -1;
233 n = 0;
234 if (s[0] == 0x1f)
235 {
236 if (s[1] == 0x8b)
237 n = 'g';
238 else if (s[1] == 0x9d)
239 n = 'c';
240 }
241 else if (s[0] == 0xd6 && s[1] == 0xc3 && s[2] == 0xc4 && s[3] == 0xd8)
242 n = 'v';
243 sfread(sp, s, 0);
244 if (!n)
245 return 0;
246 if (flags & SFGZ_VERIFY)
247 return n != 0;
248 switch (n)
249 {
250 case 'c':
251 return (r = sfdclzw(sp, flags)) > 0 ? 'c' : r;
252 case 'v':
253 r = 0;
254 n = dup(0);
255 close(0);
256 if (dup(sffileno(sp)) || !sfpopen(sp, "vcunzip", "r"))
257 r = -1;
258 close(0);
259 if (n > 0 && dup(n))
260 r = -1;
261 close(n);
262 return r > 0 ? 'v' : r;
263 }
264 }
265 else if (flags & SFGZ_VERIFY)
266 return -1;
267 if (!(gz = newof(0, Sfgzip_t, 1, 0)))
268 return -1;
269 gz->disc.exceptf = sfgzexcept;
270 if (rd)
271 gz->disc.readf = sfgzread;
272 else
273 gz->disc.writef = sfgzwrite;
274 gz->disc.seekf = sfgzseek;
275 m = mode;
276 *m++ = rd ? 'r' : 'w';
277 *m++ = 'b';
278 if (flags & SFGZ_NOCRC)
279 *m++ = 'n';
280 *m++ = 'o';
281 if ((flags &= 0xf) > 0 && flags <= 9)
282 *m++ = '0' + flags;
283 *m = 0;
284 #if PRIVATE
285 sfset(sp, SF_SHARE|SF_PUBLIC, 0);
286 #endif
287 if (!rd)
288 {
289 m = 0;
290 z = 0;
291 }
292 else if (!(z = sfreserve(sp, 0, -1) ? (size_t)sfvalue(sp) : 0))
293 m = 0;
294 else if (m = sfreserve(sp, z, 0))
295 z = (size_t)sfvalue(sp);
296 else
297 z = 0;
298 fd = sffileno(sp);
299 if (rd && (gz->op = sfopen(NiL, "/dev/null", "r")))
300 sfswap(sp, gz->op);
301 if (!(gz->gz = gzbopen(fd, mode, m, z)) || sfdisc(sp, &gz->disc) != &gz->disc)
302 {
303 free(gz);
304 return -1;
305 }
306 #if PRIVATE
307 #if 0
308 {
309 char* v;
310 long n;
311
312 if ((v = getenv("SFGZ_sfdcgzip_bufsize")) || (v = getenv("SFGZ_bufsize")))
313 {
314 if ((n = strtol(v, NiL, 0)) > 0)
315 sfsetbuf(sp, NiL, n);
316 }
317 else
318 sfsetbuf(sp, NiL, SF_BUFSIZE);
319 }
320 #else
321 sfsetbuf(sp, NiL, SF_BUFSIZE);
322 #endif
323 #endif
324 if (!rd)
325 sfset(sp, SF_IOCHECK, 1);
326 return 'g';
327 }
328
329 #if __OBSOLETE__ < 19990717
330
331 #if defined(__EXPORT__)
332 #define extern __EXPORT__
333 #endif
334
335 extern int
sfgzip(Sfio_t * sp)336 sfgzip(Sfio_t* sp)
337 {
338 return sfdcgzip(sp, 0);
339 }
340
341 #undef extern
342
343 #endif
344