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