1 /** \file znzlib.c
2 \brief Low level i/o interface to compressed and noncompressed files.
3 Written by Mark Jenkinson, FMRIB
4
5 This library provides an interface to both compressed (gzip/zlib) and
6 uncompressed (normal) file IO. The functions are written to have the
7 same interface as the standard file IO functions.
8
9 To use this library instead of normal file IO, the following changes
10 are required:
11 - replace all instances of FILE* with znzFile
12 - change the name of all function calls, replacing the initial character
13 f with the znz (e.g. fseek becomes znzseek)
14 one exception is rewind() -> znzrewind()
15 - add a third parameter to all calls to znzopen (previously fopen)
16 that specifies whether to use compression (1) or not (0)
17 - use znz_isnull rather than any (pointer == NULL) comparisons in the code
18 for znzfile types (normally done after a return from znzopen)
19
20 NB: seeks for writable files with compression are quite restricted
21
22 */
23 #ifdef ZNZ
24 #include <zlib.h>
25 #include "znzlib.h"
26 #include "sighandler.h"
27 /*
28 znzlib.c (zipped or non-zipped library)
29
30 ***** This code is released to the public domain. *****
31
32 ***** Author: Mark Jenkinson, FMRIB Centre, University of Oxford *****
33 ***** Date: September 2004 *****
34
35 ***** Neither the FMRIB Centre, the University of Oxford, nor any of *****
36 ***** its employees imply any warranty of usefulness of this software *****
37 ***** for any purpose, and do not assume any liability for damages, *****
38 ***** incidental or otherwise, caused by any use of this document. *****
39
40 */
41
42
43 /* Note extra argument (use_compression) where
44 use_compression==0 is no compression
45 use_compression!=0 uses zlib (gzip) compression
46 */
47
znzopen(const char * path,const char * mode,int use_compression)48 znzFile znzopen(const char *path, const char *mode, int use_compression)
49 {
50 znzFile file;
51 file = (znzFile) mycalloc(1L,sizeof(struct znzptr));
52 if( file == NULL ){
53 fprintf(stderr,"** ERROR: znzopen failed to alloc znzptr\n");
54 return NULL;
55 }
56
57 file->nzfptr = NULL;
58
59 #ifdef HAVE_ZLIB
60 file->zfptr = NULL;
61
62 if (use_compression) {
63 file->withz = 1;
64 if((file->zfptr = gzopen(path,mode)) == NULL) {
65 free(file);
66 file = NULL;
67 }
68 } else {
69 #endif
70
71 file->withz = 0;
72 if((file->nzfptr = fopen(path,mode)) == NULL) {
73 free(file);
74 file = NULL;
75 }
76
77 #ifdef HAVE_ZLIB
78 }
79 #endif
80
81 return file;
82 }
83
84 // added Peter Beerli 2010
85 // using zlib 1.2.5 (it is not present in 1.2.3 on macs)
znzbuffer(znzFile file,unsigned long size)86 int znzbuffer(znzFile file, unsigned long size)
87 {
88 #ifdef HAVE_GZBUFFER
89 return gzbuffer(file,size);
90 #else
91 return 0;
92 #endif
93 }
94
95
znzdopen(int fd,const char * mode,int use_compression)96 znzFile znzdopen(int fd, const char *mode, int use_compression)
97 {
98 znzFile file;
99 file = (znzFile) mycalloc(1,sizeof(struct znzptr));
100 if( file == NULL ){
101 fprintf(stderr,"** ERROR: znzdopen failed to alloc znzptr\n");
102 return NULL;
103 }
104 #ifdef HAVE_ZLIB
105 if (use_compression) {
106 file->withz = 1;
107 file->zfptr = gzdopen(fd,mode);
108 file->nzfptr = NULL;
109 } else {
110 #endif
111 file->withz = 0;
112 #ifdef HAVE_FDOPEN
113 file->nzfptr = fdopen(fd,mode);
114 #endif
115 #ifdef HAVE_ZLIB
116 file->zfptr = NULL;
117 };
118 #endif
119 return file;
120 }
121
122
Xznzclose(znzFile * file)123 int Xznzclose(znzFile * file)
124 {
125 int retval = 0;
126 if (*file!=NULL) {
127 #ifdef HAVE_ZLIB
128 if ((*file)->zfptr!=NULL) { retval = gzclose((*file)->zfptr); }
129 #endif
130 if ((*file)->nzfptr!=NULL) { retval = fclose((*file)->nzfptr); }
131
132 free(*file);
133 *file = NULL;
134 }
135 return retval;
136 }
137
138
139 /* we already assume ints are 4 bytes */
140 #undef ZNZ_MAX_BLOCK_SIZE
141 #define ZNZ_MAX_BLOCK_SIZE (1<<30)
142
znzread(void * buf,size_t size,size_t nmemb,znzFile file)143 size_t znzread(void* buf, size_t size, size_t nmemb, znzFile file)
144 {
145 size_t remain = size*nmemb;
146 char * cbuf = (char *)buf;
147 unsigned n2read;
148 int nread;
149
150 if (file==NULL) { return 0; }
151 #ifdef HAVE_ZLIB
152 if (file->zfptr!=NULL) {
153 /* gzread/write take unsigned int length, so maybe read in int pieces
154 (noted by M Hanke, example given by M Adler) 6 July 2010 [rickr] */
155 while( remain > 0 ) {
156 n2read = (remain < ZNZ_MAX_BLOCK_SIZE) ? remain : ZNZ_MAX_BLOCK_SIZE;
157 nread = gzread(file->zfptr, (void *)cbuf, n2read);
158 if( nread < 0 ) return nread; /* returns -1 on error */
159
160 remain -= nread;
161 cbuf += nread;
162
163 /* require reading n2read bytes, so we don't get stuck */
164 if( nread < (int)n2read ) break; /* return will be short */
165 }
166
167 /* warn of a short read that will seem complete */
168 if( remain > 0 && remain < size )
169 fprintf(stderr,"** znzread: read short by %u bytes\n",(unsigned)remain);
170
171 return nmemb - remain/size; /* return number of members processed */
172 }
173 #endif
174 return fread(buf,size,nmemb,file->nzfptr);
175 }
176
znzwrite(const void * buf,size_t size,size_t nmemb,znzFile file)177 size_t znzwrite(const void* buf, size_t size, size_t nmemb, znzFile file)
178 {
179 size_t remain = size*nmemb;
180 char * cbuf = (char *)buf;
181 unsigned n2write;
182 int nwritten;
183
184 if (file==NULL) { return 0; }
185 #ifdef HAVE_ZLIB
186 if (file->zfptr!=NULL) {
187 while( remain > 0 ) {
188 n2write = (remain < ZNZ_MAX_BLOCK_SIZE) ? remain : ZNZ_MAX_BLOCK_SIZE;
189 nwritten = gzwrite(file->zfptr, (void *)cbuf, n2write);
190
191 /* gzread returns 0 on error, but in case that ever changes... */
192 if( nwritten < 0 ) return nwritten;
193
194 remain -= nwritten;
195 cbuf += nwritten;
196
197 /* require writing n2write bytes, so we don't get stuck */
198 if( nwritten < (int)n2write ) break;
199 }
200
201 /* warn of a short write that will seem complete */
202 if( remain > 0 && remain < size )
203 fprintf(stderr,"** znzwrite: write short by %u bytes\n",(unsigned)remain);
204
205 return nmemb - remain/size; /* return number of members processed */
206 }
207 #endif
208 return fwrite(buf,size,nmemb,file->nzfptr);
209 }
210
znzseek(znzFile file,long offset,int whence)211 long znzseek(znzFile file, long offset, int whence)
212 {
213 if (file==NULL) { return 0; }
214 #ifdef HAVE_ZLIB
215 if (file->zfptr!=NULL) return (long) gzseek(file->zfptr,offset,whence);
216 #endif
217 return fseek(file->nzfptr,offset,whence);
218 }
219
znzrewind(znzFile stream)220 int znzrewind(znzFile stream)
221 {
222 if (stream==NULL) { return 0; }
223 #ifdef HAVE_ZLIB
224 /* On some systems, gzrewind() fails for uncompressed files.
225 Use gzseek(), instead. 10, May 2005 [rickr]
226
227 if (stream->zfptr!=NULL) return gzrewind(stream->zfptr);
228 */
229
230 if (stream->zfptr!=NULL) return (int)gzseek(stream->zfptr, 0L, SEEK_SET);
231 #endif
232 rewind(stream->nzfptr);
233 return 0;
234 }
235
znztell(znzFile file)236 long znztell(znzFile file)
237 {
238 if (file==NULL) { return 0; }
239 #ifdef HAVE_ZLIB
240 if (file->zfptr!=NULL) return (long) gztell(file->zfptr);
241 #endif
242 return ftell(file->nzfptr);
243 }
244
znzputs(const char * str,znzFile file)245 int znzputs(const char * str, znzFile file)
246 {
247 if (file==NULL) { return 0; }
248 #ifdef HAVE_ZLIB
249 if (file->zfptr!=NULL) return gzputs(file->zfptr,str);
250 #endif
251 return fputs(str,file->nzfptr);
252 }
253
254
znzgets(char * str,int size,znzFile file)255 char * znzgets(char* str, int size, znzFile file)
256 {
257 if (file==NULL) { return NULL; }
258 #ifdef HAVE_ZLIB
259 if (file->zfptr!=NULL) return gzgets(file->zfptr,str,size);
260 #endif
261 return fgets(str,size,file->nzfptr);
262 }
263
264
znzflush(znzFile file)265 int znzflush(znzFile file)
266 {
267 if (file==NULL) { return 0; }
268 #ifdef HAVE_ZLIB
269 if (file->zfptr!=NULL) return gzflush(file->zfptr,Z_SYNC_FLUSH);
270 #endif
271 return fflush(file->nzfptr);
272 }
273
274
znzeof(znzFile file)275 int znzeof(znzFile file)
276 {
277 if (file==NULL) { return 0; }
278 #ifdef HAVE_ZLIB
279 if (file->zfptr!=NULL) return gzeof(file->zfptr);
280 #endif
281 return feof(file->nzfptr);
282 }
283
284
znzputc(int c,znzFile file)285 int znzputc(int c, znzFile file)
286 {
287 if (file==NULL) { return 0; }
288 #ifdef HAVE_ZLIB
289 if (file->zfptr!=NULL) return gzputc(file->zfptr,c);
290 #endif
291 return fputc(c,file->nzfptr);
292 }
293
znzungetc(int c,znzFile file)294 int znzungetc(int c, znzFile file)
295 {
296 if (file==NULL) { return 0; }
297 #ifdef HAVE_ZLIB
298 if (file->zfptr!=NULL) return gzungetc(c, file->zfptr);
299 #endif
300 return ungetc(c,file->nzfptr);
301 }
302
znzgetc(znzFile file)303 int znzgetc(znzFile file)
304 {
305 if (file==NULL) { return 0; }
306 #ifdef HAVE_ZLIB
307 if (file->zfptr!=NULL) return gzgetc(file->zfptr);
308 #endif
309 return fgetc(file->nzfptr);
310 }
311
312 #if !defined (WIN32)
znzprintf(znzFile stream,const char * format,...)313 int znzprintf(znzFile stream, const char *format, ...)
314 {
315 int retval=0;
316 char *tmpstr;
317 va_list va;
318 if (stream==NULL) { return 0; }
319 va_start(va, format);
320 #ifdef HAVE_ZLIB
321 if (stream->zfptr!=NULL) {
322 int size; /* local to HAVE_ZLIB block */
323 size = strlen(format) + 1000000; /* overkill I hope */
324 tmpstr = (char *) mycalloc(1L, size);
325 if( tmpstr == NULL ){
326 fprintf(stderr,"** ERROR: znzprintf failed to alloc %d bytes\n", size);
327 return retval;
328 }
329 vsprintf(tmpstr,format,va);
330 retval=gzprintf(stream->zfptr,"%s",tmpstr);
331 free(tmpstr);
332 } else
333 #endif
334 {
335 retval=vfprintf(stream->nzfptr,format,va);
336 }
337 va_end(va);
338 return retval;
339 }
340
341 #endif
342
343 #endif
344