GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/nrrd/gzio.c Lines: 0 240 0.0 %
Date: 2017-05-26 Branches: 0 176 0.0 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
/*
24
  This file is a modified version of the 'gzio.c' and 'zutil.h' source
25
  files from the zlib 1.1.4 distribution.
26
27
  zlib.h -- interface of the 'zlib' general purpose compression library
28
  version 1.1.4, March 11th, 2002
29
30
  Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler
31
32
  This software is provided 'as-is', without any express or implied
33
  warranty.  In no event will the authors be held liable for any damages
34
  arising from the use of this software.
35
36
  Permission is granted to anyone to use this software for any purpose,
37
  including commercial applications, and to alter it and redistribute it
38
  freely, subject to the following restrictions:
39
40
  1. The origin of this software must not be misrepresented; you must not
41
     claim that you wrote the original software. If you use this software
42
     in a product, an acknowledgment in the product documentation would be
43
     appreciated but is not required.
44
  2. Altered source versions must be plainly marked as such, and must not be
45
     misrepresented as being the original software.
46
  3. This notice may not be removed or altered from any source distribution.
47
48
  Jean-loup Gailly        Mark Adler
49
  jloup@gzip.org          madler@alumni.caltech.edu
50
51
  The data format used by the zlib library is described by RFCs (Request for
52
  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
53
  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
54
*/
55
56
#if TEEM_ZLIB
57
58
#include "nrrd.h"
59
#include "privateNrrd.h"
60
61
#ifdef _WIN32 /* Window 95 & Windows NT */
62
#  define _NRRD_OS_CODE  0x0b
63
#endif
64
65
#if defined(MACOS) || defined(TARGET_OS_MAC) || defined(__APPLE_CC__)
66
#  define _NRRD_OS_CODE  0x07
67
#endif
68
69
#ifndef _NRRD_OS_CODE
70
#  define _NRRD_OS_CODE  0x03  /* assume Unix */
71
#endif
72
73
/* default memLevel */
74
#if MAX_MEM_LEVEL >= 8
75
#  define _NRRD_DEF_MEM_LEVEL 8
76
#else
77
#  define _NRRD_DEF_MEM_LEVEL  MAX_MEM_LEVEL
78
#endif
79
80
/* stream buffer size */
81
#define _NRRD_Z_BUFSIZE 16 * 1024
82
83
/* gzip flag byte */
84
#define _NRRD_ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
85
#define _NRRD_HEAD_CRC     0x02 /* bit 1 set: header CRC present */
86
#define _NRRD_EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
87
#define _NRRD_ORIG_NAME    0x08 /* bit 3 set: original file name present */
88
#define _NRRD_COMMENT      0x10 /* bit 4 set: file comment present */
89
#define _NRRD_RESERVED     0xE0 /* bits 5..7: reserved */
90
91
typedef struct _NrrdGzStream {
92
  z_stream stream;
93
  int      z_err;   /* error code for last stream operation */
94
  int      z_eof;   /* set if end of input file */
95
  FILE     *file;   /* .gz file */
96
  Byte     *inbuf;  /* input buffer */
97
  Byte     *outbuf; /* output buffer */
98
  uLong    crc;     /* crc32 of uncompressed data */
99
  char     *msg;    /* error message */
100
  int      transparent; /* 1 if input file is not a .gz file */
101
  char     mode;    /* 'w' or 'r' */
102
  long     startpos; /* start of compressed data in file (header skipped) */
103
} _NrrdGzStream;
104
105
static int _nrrdGzMagic[2] = {0x1f, 0x8b}; /* gzip magic header */
106
107
/* zlib error messages */
108
static const char *_nrrdGzErrMsg[10] = {
109
  "need dictionary",     /* Z_NEED_DICT       2  */
110
  "stream end",          /* Z_STREAM_END      1  */
111
  "",                    /* Z_OK              0  */
112
  "file error",          /* Z_ERRNO         (-1) */
113
  "stream error",        /* Z_STREAM_ERROR  (-2) */
114
  "data error",          /* Z_DATA_ERROR    (-3) */
115
  "insufficient memory", /* Z_MEM_ERROR     (-4) */
116
  "buffer error",        /* Z_BUF_ERROR     (-5) */
117
  "incompatible version",/* Z_VERSION_ERROR (-6) */
118
  ""};
119
120
#define _NRRD_GZ_ERR_MSG(err) _nrrdGzErrMsg[Z_NEED_DICT-(err)]
121
122
/* some forward declarations for things in this file */
123
static void _nrrdGzCheckHeader(_NrrdGzStream *s);
124
static int _nrrdGzDestroy(_NrrdGzStream *s);
125
static int _nrrdGzDoFlush(gzFile file, int flush);
126
static void _nrrdGzPutLong(FILE *file, uLong x);
127
static uLong _nrrdGzGetLong(_NrrdGzStream *s);
128
129
/*
130
** _nrrdGzOpen()
131
**
132
** Opens a gzip (.gz) file for reading or writing. The mode parameter
133
** is like in fopen ("rb" or "wb"). The file represented by the FILE* pointer
134
** should be open already with the same mode.  The mode parameter can also be
135
** used to specify the compression level "[0-9]" and strategy "[f|h]".
136
**
137
** The compression level must be between 0 and 9: 1 gives best speed,
138
** 9 gives best compression, 0 gives no compression at all (the input data
139
** is simply copied a block at a time). The default level is 6.
140
**
141
** The strategy parameter is used to tune the compression algorithm. Use
142
** "f" for data produced by a filter (or predictor), or "h" to force Huffman
143
** encoding only (no string match). Filtered data consists mostly of small
144
** values with a somewhat random distribution. In this case, the compression
145
** algorithm is tuned to compress them better. The effect of "f" is to force
146
** more Huffman coding and less string matching; it is somewhat intermediate
147
** between the default and Huffman. The strategy parameter only affects the
148
** compression ratio but not the correctness of the compressed output even
149
** if it is not set appropriately.
150
**
151
** The complete syntax for the mode parameter is: "(r|w[a])[0-9][f|h]".
152
**
153
** Returns Z_NULL if the file could not be opened or if there was
154
** insufficient memory to allocate the (de)compression state; errno
155
** can be checked to distinguish the two cases (if errno is zero, the
156
** zlib error is Z_MEM_ERROR).
157
*/
158
gzFile
159
_nrrdGzOpen(FILE* fd, const char* mode) {
160
  static const char me[]="_nrrdGzOpen";
161
  int error;
162
  int level = Z_DEFAULT_COMPRESSION; /* compression level */
163
  int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
164
  const char *p = mode;
165
  _NrrdGzStream *s;
166
  char fmode[AIR_STRLEN_MED]; /* copy of mode, without the compression level */
167
  char *m = fmode;
168
169
  if (!mode) {
170
    biffAddf(NRRD, "%s: no file mode specified", me);
171
    return Z_NULL;
172
  }
173
  /* allocate stream struct */
174
  s = (_NrrdGzStream *)calloc(1, sizeof(_NrrdGzStream));
175
  if (!s) {
176
    biffAddf(NRRD, "%s: failed to allocate stream buffer", me);
177
    return Z_NULL;
178
  }
179
  /* initialize stream struct */
180
  s->stream.zalloc = (alloc_func)0;
181
  s->stream.zfree = (free_func)0;
182
  s->stream.opaque = (voidpf)0;
183
  s->stream.next_in = s->inbuf = Z_NULL;
184
  s->stream.next_out = s->outbuf = Z_NULL;
185
  s->stream.avail_in = s->stream.avail_out = 0;
186
  s->file = NULL;
187
  s->z_err = Z_OK;
188
  s->z_eof = 0;
189
  s->crc = crc32(0L, Z_NULL, 0);
190
  s->msg = NULL;
191
  s->transparent = 0;
192
  /* parse mode flag */
193
  s->mode = '\0';
194
  do {
195
    if (*p == 'r') s->mode = 'r';
196
    if (*p == 'w' || *p == 'a') s->mode = 'w';
197
    if (*p >= '0' && *p <= '9') {
198
      level = *p - '0';
199
    } else if (*p == 'f') {
200
      strategy = Z_FILTERED;
201
    } else if (*p == 'h') {
202
      strategy = Z_HUFFMAN_ONLY;
203
    } else {
204
      *m++ = *p; /* copy the mode */
205
    }
206
  } while (*p++ && m != fmode + sizeof(fmode));
207
  if (s->mode == '\0') {
208
    biffAddf(NRRD, "%s: invalid file mode", me);
209
    return _nrrdGzDestroy(s), (gzFile)Z_NULL;
210
  }
211
212
  if (s->mode == 'w') {
213
    error = deflateInit2(&(s->stream), level,
214
                         Z_DEFLATED, -MAX_WBITS, _NRRD_DEF_MEM_LEVEL,
215
                         strategy);
216
    /* windowBits is passed < 0 to suppress zlib header */
217
218
    s->stream.next_out = s->outbuf = (Byte*)calloc(1, _NRRD_Z_BUFSIZE);
219
    if (error != Z_OK || s->outbuf == Z_NULL) {
220
      biffAddf(NRRD, "%s: stream init failed", me);
221
      return _nrrdGzDestroy(s), (gzFile)Z_NULL;
222
    }
223
  } else {
224
    s->stream.next_in  = s->inbuf = (Byte*)calloc(1, _NRRD_Z_BUFSIZE);
225
226
    error = inflateInit2(&(s->stream), -MAX_WBITS);
227
    /* windowBits is passed < 0 to tell that there is no zlib header.
228
     * Note that in this case inflate *requires* an extra "dummy" byte
229
     * after the compressed stream in order to complete decompression and
230
     * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
231
     * present after the compressed stream.
232
     */
233
    if (error != Z_OK || s->inbuf == Z_NULL) {
234
      biffAddf(NRRD, "%s: stream init failed", me);
235
      return _nrrdGzDestroy(s), (gzFile)Z_NULL;
236
    }
237
  }
238
  s->stream.avail_out = _NRRD_Z_BUFSIZE;
239
  errno = 0;
240
  s->file = fd;
241
  if (s->file == NULL) {
242
    biffAddf(NRRD, "%s: null file pointer", me);
243
    return _nrrdGzDestroy(s), (gzFile)Z_NULL;
244
  }
245
  if (s->mode == 'w') {
246
    /* Write a very simple .gz header: */
247
    fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", _nrrdGzMagic[0], _nrrdGzMagic[1],
248
            Z_DEFLATED,
249
            0 /*flags*/,
250
            0,0,0,0 /*time*/,
251
            0 /*xflags*/,
252
            _NRRD_OS_CODE);
253
    s->startpos = 10L;
254
    /* We use 10L instead of ftell(s->file) to because ftell causes an
255
     * fflush on some systems. This version of the library doesn't use
256
     * startpos anyway in write mode, so this initialization is not
257
     * necessary.
258
     */
259
  } else {
260
    _nrrdGzCheckHeader(s); /* skip the .gz header */
261
    s->startpos = (ftell(s->file) - s->stream.avail_in);
262
  }
263
  return (gzFile)s;
264
}
265
266
/*
267
** _nrrdGzClose()
268
**
269
** Flushes all pending output if necessary, closes the compressed file
270
** and deallocates the (de)compression state.
271
*/
272
int
273
_nrrdGzClose (gzFile file) {
274
  static const char me[]="_nrrdGzClose";
275
  int error;
276
  _NrrdGzStream *s = (_NrrdGzStream*)file;
277
278
  if (s == NULL) {
279
    biffAddf(NRRD, "%s: invalid stream", me);
280
    return 1;
281
  }
282
  if (s->mode == 'w') {
283
    error = _nrrdGzDoFlush(file, Z_FINISH);
284
    if (error != Z_OK) {
285
      biffAddf(NRRD, "%s: failed to flush pending data", me);
286
      return _nrrdGzDestroy((_NrrdGzStream*)file);
287
    }
288
    _nrrdGzPutLong(s->file, s->crc);
289
    _nrrdGzPutLong(s->file, s->stream.total_in);
290
  }
291
  return _nrrdGzDestroy((_NrrdGzStream*)file);
292
}
293
294
/*
295
** _nrrdGzRead()
296
**
297
** Reads the given number of uncompressed bytes from the compressed file.
298
** Returns the number of bytes actually read (0 for end of file).
299
*/
300
int
301
_nrrdGzRead(gzFile file, void* buf, unsigned int len, unsigned int* didread) {
302
  static const char me[]="_nrrdGzRead";
303
  _NrrdGzStream *s = (_NrrdGzStream*)file;
304
  Bytef *start = (Bytef*)buf; /* starting point for crc computation */
305
  Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
306
307
  if (s == NULL || s->mode != 'r') {
308
    biffAddf(NRRD, "%s: invalid stream or file mode", me);
309
    *didread = 0;
310
    return 1;
311
  }
312
313
  if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) {
314
    biffAddf(NRRD, "%s: data read error", me);
315
    *didread = 0;
316
    return 1;
317
  }
318
319
  if (s->z_err == Z_STREAM_END) {
320
    *didread = 0;
321
    return 0;  /* EOF */
322
  }
323
324
  next_out = (Byte*)buf;
325
  s->stream.next_out = (Bytef*)buf;
326
  s->stream.avail_out = len;
327
328
  while (s->stream.avail_out != 0) {
329
330
    if (s->transparent) {
331
      /* Copy first the lookahead bytes: */
332
      uInt n = s->stream.avail_in;
333
      if (n > s->stream.avail_out) n = s->stream.avail_out;
334
      if (n > 0) {
335
        memcpy(s->stream.next_out, s->stream.next_in, n);
336
        next_out += n;
337
        s->stream.next_out = next_out;
338
        s->stream.next_in   += n;
339
        s->stream.avail_out -= n;
340
        s->stream.avail_in  -= n;
341
      }
342
      if (s->stream.avail_out > 0) {
343
        s->stream.avail_out -= (uInt)fread(next_out, 1, s->stream.avail_out,
344
                                           s->file);
345
      }
346
      len -= s->stream.avail_out;
347
      s->stream.total_in  += len;
348
      s->stream.total_out += len;
349
      if (len == 0) s->z_eof = 1;
350
      *didread = len;
351
      return 0;
352
    }
353
    if (s->stream.avail_in == 0 && !s->z_eof) {
354
355
      errno = 0;
356
      s->stream.avail_in = (uInt)fread(s->inbuf, 1, _NRRD_Z_BUFSIZE, s->file);
357
      if (s->stream.avail_in == 0) {
358
        s->z_eof = 1;
359
        if (ferror(s->file)) {
360
          s->z_err = Z_ERRNO;
361
          break;
362
        }
363
      }
364
      s->stream.next_in = s->inbuf;
365
    }
366
    s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
367
368
    if (s->z_err == Z_STREAM_END) {
369
      /* Check CRC and original size */
370
      s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
371
      start = s->stream.next_out;
372
373
      if (_nrrdGzGetLong(s) != s->crc) {
374
        s->z_err = Z_DATA_ERROR;
375
      } else {
376
        (void)_nrrdGzGetLong(s);
377
        /* The uncompressed length returned by above getlong() may
378
         * be different from s->stream.total_out) in case of
379
         * concatenated .gz files. Check for such files:
380
         */
381
        _nrrdGzCheckHeader(s);
382
        if (s->z_err == Z_OK) {
383
          uLong total_in = s->stream.total_in;
384
          uLong total_out = s->stream.total_out;
385
386
          inflateReset(&(s->stream));
387
          s->stream.total_in = total_in;
388
          s->stream.total_out = total_out;
389
          s->crc = crc32(0L, Z_NULL, 0);
390
        }
391
      }
392
    }
393
    if (s->z_err != Z_OK || s->z_eof) break;
394
  }
395
  s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
396
397
  *didread = len - s->stream.avail_out;
398
  return 0;
399
}
400
401
/*
402
** _nrrdGzWrite()
403
**
404
** Writes the given number of uncompressed bytes into the compressed file.
405
** Returns the number of bytes actually written (0 in case of error).
406
*/
407
int
408
_nrrdGzWrite(gzFile file, const void* buf, unsigned int len,
409
             unsigned int* written) {
410
  static const char me[]="_nrrdGzWrite";
411
  _NrrdGzStream *s = (_NrrdGzStream*)file;
412
  void *nonconstbuf;
413
414
  if (s == NULL || s->mode != 'w') {
415
    biffAddf(NRRD, "%s: invalid stream or file mode", me);
416
    *written = 0;
417
    return 1;
418
  }
419
420
  /* If you google for "const correct zlib" or "zlib.h is not
421
     const-correct" you'll find zlib mailing list discussions of how
422
     zlib doesn't have all the consts that it should, and various code
423
     examples of using multiple casts to hide the problem. Here's a
424
     slow way that doesn't use mere casting to make the const go away */
425
  memcpy(&nonconstbuf, &buf, sizeof(void*));
426
  s->stream.next_in = (Bytef*)nonconstbuf;
427
  s->stream.avail_in = len;
428
429
  while (s->stream.avail_in != 0) {
430
    if (s->stream.avail_out == 0) {
431
      s->stream.next_out = s->outbuf;
432
      if (fwrite(s->outbuf, 1, _NRRD_Z_BUFSIZE, s->file) != _NRRD_Z_BUFSIZE) {
433
        s->z_err = Z_ERRNO;
434
        biffAddf(NRRD, "%s: failed to write to file", me);
435
        break;
436
      }
437
      s->stream.avail_out = _NRRD_Z_BUFSIZE;
438
    }
439
    s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
440
    if (s->z_err != Z_OK) break;
441
  }
442
  s->crc = crc32(s->crc, (const Bytef *)buf, len);
443
444
  *written = len - s->stream.avail_in;
445
  return 0;
446
}
447
448
/*
449
** _nrrdGzGetByte()
450
**
451
** Reads a byte from a _NrrdGzStream. Updates next_in and avail_in.
452
** Returns EOF for end of file.
453
** IN assertion: the stream s has been sucessfully opened for reading.
454
*/
455
static int
456
_nrrdGzGetByte(_NrrdGzStream *s) {
457
  static const char me[]="_nrrdGzGetByte";
458
459
  if (s->z_eof) return EOF;
460
  if (s->stream.avail_in == 0) {
461
    errno = 0;
462
    s->stream.avail_in = (uInt)fread(s->inbuf, 1, _NRRD_Z_BUFSIZE, s->file);
463
    if (s->stream.avail_in == 0) {
464
      s->z_eof = 1;
465
      if (ferror(s->file)) {
466
        biffAddf(NRRD, "%s: failed to read from file", me);
467
        s->z_err = Z_ERRNO;
468
      }
469
      return EOF;
470
    }
471
    s->stream.next_in = s->inbuf;
472
  }
473
  s->stream.avail_in--;
474
  return *(s->stream.next_in)++;
475
}
476
477
/*
478
******** _nrrdGzCheckHeader()
479
**
480
** Checks the gzip header of a _NrrdGzStream opened for reading. Sets
481
** the stream mode to transparent if the gzip magic header is not
482
** present; sets s->err to Z_DATA_ERROR if the magic header is present
483
** but the rest of the header is incorrect.
484
** IN assertion: the stream s has already been created sucessfully;
485
** s->stream.avail_in is zero for the first time, but may be non-zero
486
** for concatenated .gz files.
487
*/
488
static void
489
_nrrdGzCheckHeader(_NrrdGzStream *s) {
490
  static const char me[]="_nrrdGzCheckHeader";
491
  int method; /* method byte */
492
  int flags;  /* flags byte */
493
  uInt len;
494
  int c;
495
496
  /* Check the gzip magic header */
497
  for (len = 0; len < 2; len++) {
498
    c = _nrrdGzGetByte(s);
499
    if (c != _nrrdGzMagic[len]) {
500
      if (len != 0) s->stream.avail_in++, s->stream.next_in--;
501
      if (c != EOF) {
502
        s->stream.avail_in++, s->stream.next_in--;
503
        s->transparent = 1;
504
      }
505
      s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
506
      return;
507
    }
508
  }
509
  method = _nrrdGzGetByte(s);
510
  flags = _nrrdGzGetByte(s);
511
  if (method != Z_DEFLATED || (flags & _NRRD_RESERVED) != 0) {
512
    biffAddf(NRRD, "%s: gzip compression method is not deflate", me);
513
    s->z_err = Z_DATA_ERROR;
514
    return;
515
  }
516
517
  /* Discard time, xflags and OS code: */
518
  for (len = 0; len < 6; len++) (void)_nrrdGzGetByte(s);
519
520
  if ((flags & _NRRD_EXTRA_FIELD) != 0) { /* skip the extra field */
521
    len  =  (uInt)_nrrdGzGetByte(s);
522
    len += ((uInt)_nrrdGzGetByte(s))<<8;
523
    /* len is garbage if EOF but the loop below will quit anyway */
524
    while (len-- != 0 && _nrrdGzGetByte(s) != EOF) ;
525
  }
526
  if ((flags & _NRRD_ORIG_NAME) != 0) { /* skip the original file name */
527
    while ((c = _nrrdGzGetByte(s)) != 0 && c != EOF) ;
528
  }
529
  if ((flags & _NRRD_COMMENT) != 0) {   /* skip the .gz file comment */
530
    while ((c = _nrrdGzGetByte(s)) != 0 && c != EOF) ;
531
  }
532
  if ((flags & _NRRD_HEAD_CRC) != 0) {  /* skip the header crc */
533
    for (len = 0; len < 2; len++) (void)_nrrdGzGetByte(s);
534
  }
535
  s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
536
}
537
538
/*
539
** _nrrdGzDestroy()
540
**
541
** Cleans up then free the given _NrrdGzStream. Returns a zlib error code.
542
** Try freeing in the reverse order of allocations.  FILE* s->file is not
543
** closed.  Because we didn't allocate it, we shouldn't delete it.
544
*/
545
static int
546
_nrrdGzDestroy(_NrrdGzStream *s) {
547
  static const char me[]="_nrrdGzDestroy";
548
  int error = Z_OK;
549
550
  if (s == NULL) {
551
    biffAddf(NRRD, "%s: invalid stream", me);
552
    return 1;
553
  }
554
  s->msg = (char *)airFree(s->msg);
555
  if (s->stream.state != NULL) {
556
    if (s->mode == 'w') {
557
      error = deflateEnd(&(s->stream));
558
    } else if (s->mode == 'r') {
559
      error = inflateEnd(&(s->stream));
560
    }
561
  }
562
  if (error != Z_OK) {
563
    biffAddf(NRRD, "%s: %s", me, _NRRD_GZ_ERR_MSG(error));
564
  }
565
  if (s->z_err < 0) error = s->z_err;
566
  if (error != Z_OK) {
567
    biffAddf(NRRD, "%s: %s", me, _NRRD_GZ_ERR_MSG(error));
568
  }
569
  s->inbuf = (Byte *)airFree(s->inbuf);
570
  s->outbuf = (Byte *)airFree(s->outbuf);
571
  airFree(s);   /* avoiding unused value warnings, no NULL set */
572
  return error != Z_OK;
573
}
574
575
/*
576
** _nrrdGzDoFlush()
577
**
578
** Flushes all pending output into the compressed file. The parameter
579
** flush is the same as in the deflate() function.
580
*/
581
static int
582
_nrrdGzDoFlush(gzFile file, int flush) {
583
  static const char me[]="_nrrdGzDoFlush";
584
  uInt len;
585
  int done = 0;
586
  _NrrdGzStream *s = (_NrrdGzStream*)file;
587
588
  if (s == NULL || s->mode != 'w') {
589
    biffAddf(NRRD, "%s: invalid stream or file mode", me);
590
    return Z_STREAM_ERROR;
591
  }
592
593
  s->stream.avail_in = 0; /* should be zero already anyway */
594
595
  for (;;) {
596
    len = _NRRD_Z_BUFSIZE - s->stream.avail_out;
597
598
    if (len != 0) {
599
      if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
600
        s->z_err = Z_ERRNO;
601
        return Z_ERRNO;
602
      }
603
      s->stream.next_out = s->outbuf;
604
      s->stream.avail_out = _NRRD_Z_BUFSIZE;
605
    }
606
    if (done) break;
607
    s->z_err = deflate(&(s->stream), flush);
608
609
    /* Ignore the second of two consecutive flushes: */
610
    if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
611
612
    /* deflate has finished flushing only when it hasn't used up
613
     * all the available space in the output buffer:
614
     */
615
    done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
616
617
    if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
618
  }
619
  return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
620
}
621
622
/*
623
** _nrrdGzPutLong()
624
**
625
** Outputs a long in LSB order to the given file.
626
*/
627
static void
628
_nrrdGzPutLong(FILE* file, uLong x) {
629
  int n;
630
  for (n = 0; n < 4; n++) {
631
    fputc((int)(x & 0xff), file);
632
    x >>= 8;
633
  }
634
}
635
636
/*
637
** _nrrdGzGetLong()
638
**
639
** Reads a long in LSB order from the given _NrrdGzStream.
640
** Sets z_err in case of error.
641
*/
642
static uLong
643
_nrrdGzGetLong(_NrrdGzStream *s) {
644
  uLong x = (uLong)_nrrdGzGetByte(s);
645
  int c;
646
647
  x += ((uLong)_nrrdGzGetByte(s))<<8;
648
  x += ((uLong)_nrrdGzGetByte(s))<<16;
649
  c = _nrrdGzGetByte(s);
650
  if (c == EOF) s->z_err = Z_DATA_ERROR;
651
  x += ((uLong)c)<<24;
652
  return x;
653
}
654
655
#endif /* TEEM_ZLIB */
656
657
/*
658
** random symbol to have in object file, even when Zlib not enabled
659
*/
660
int
661
_nrrdGzDummySymbol(void) {
662
  return 42;
663
}
664