~maria-captains/mariadb-native-client/trunk

« back to all changes in this revision

Viewing changes to zlib/gzread.c

  • Committer: ghost
  • Date: 2011-10-10 11:01:17 UTC
  • Revision ID: ghost@work-20111010110117-a2zv9mgwavp0iw0a
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* gzread.c -- zlib functions for reading gzip files
 
2
 * Copyright (C) 2004, 2005, 2010 Mark Adler
 
3
 * For conditions of distribution and use, see copyright notice in zlib.h
 
4
 */
 
5
 
 
6
#include "gzguts.h"
 
7
 
 
8
/* Local functions */
 
9
local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
 
10
local int gz_avail OF((gz_statep));
 
11
local int gz_next4 OF((gz_statep, unsigned long *));
 
12
local int gz_head OF((gz_statep));
 
13
local int gz_decomp OF((gz_statep));
 
14
local int gz_make OF((gz_statep));
 
15
local int gz_skip OF((gz_statep, z_off64_t));
 
16
 
 
17
/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
 
18
   state->fd, and update state->eof, state->err, and state->msg as appropriate.
 
19
   This function needs to loop on read(), since read() is not guaranteed to
 
20
   read the number of bytes requested, depending on the type of descriptor. */
 
21
local int gz_load(state, buf, len, have)
 
22
    gz_statep state;
 
23
    unsigned char *buf;
 
24
    unsigned len;
 
25
    unsigned *have;
 
26
{
 
27
    int ret;
 
28
 
 
29
    *have = 0;
 
30
    do {
 
31
        ret = read(state->fd, buf + *have, len - *have);
 
32
        if (ret <= 0)
 
33
            break;
 
34
        *have += ret;
 
35
    } while (*have < len);
 
36
    if (ret < 0) {
 
37
        gz_error(state, Z_ERRNO, zstrerror());
 
38
        return -1;
 
39
    }
 
40
    if (ret == 0)
 
41
        state->eof = 1;
 
42
    return 0;
 
43
}
 
44
 
 
45
/* Load up input buffer and set eof flag if last data loaded -- return -1 on
 
46
   error, 0 otherwise.  Note that the eof flag is set when the end of the input
 
47
   file is reached, even though there may be unused data in the buffer.  Once
 
48
   that data has been used, no more attempts will be made to read the file.
 
49
   gz_avail() assumes that strm->avail_in == 0. */
 
50
local int gz_avail(state)
 
51
    gz_statep state;
 
52
{
 
53
    z_streamp strm = &(state->strm);
 
54
 
 
55
    if (state->err != Z_OK)
 
56
        return -1;
 
57
    if (state->eof == 0) {
 
58
        if (gz_load(state, state->in, state->size,
 
59
                (unsigned *)&(strm->avail_in)) == -1)
 
60
            return -1;
 
61
        strm->next_in = state->in;
 
62
    }
 
63
    return 0;
 
64
}
 
65
 
 
66
/* Get next byte from input, or -1 if end or error. */
 
67
#define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \
 
68
                (strm->avail_in == 0 ? -1 : \
 
69
                 (strm->avail_in--, *(strm->next_in)++)))
 
70
 
 
71
/* Get a four-byte little-endian integer and return 0 on success and the value
 
72
   in *ret.  Otherwise -1 is returned and *ret is not modified. */
 
73
local int gz_next4(state, ret)
 
74
    gz_statep state;
 
75
    unsigned long *ret;
 
76
{
 
77
    int ch;
 
78
    unsigned long val;
 
79
    z_streamp strm = &(state->strm);
 
80
 
 
81
    val = NEXT();
 
82
    val += (unsigned)NEXT() << 8;
 
83
    val += (unsigned long)NEXT() << 16;
 
84
    ch = NEXT();
 
85
    if (ch == -1)
 
86
        return -1;
 
87
    val += (unsigned long)ch << 24;
 
88
    *ret = val;
 
89
    return 0;
 
90
}
 
91
 
 
92
/* Look for gzip header, set up for inflate or copy.  state->have must be zero.
 
93
   If this is the first time in, allocate required memory.  state->how will be
 
94
   left unchanged if there is no more input data available, will be set to COPY
 
95
   if there is no gzip header and direct copying will be performed, or it will
 
96
   be set to GZIP for decompression, and the gzip header will be skipped so
 
97
   that the next available input data is the raw deflate stream.  If direct
 
98
   copying, then leftover input data from the input buffer will be copied to
 
99
   the output buffer.  In that case, all further file reads will be directly to
 
100
   either the output buffer or a user buffer.  If decompressing, the inflate
 
101
   state and the check value will be initialized.  gz_head() will return 0 on
 
102
   success or -1 on failure.  Failures may include read errors or gzip header
 
103
   errors.  */
 
104
local int gz_head(state)
 
105
    gz_statep state;
 
106
{
 
107
    z_streamp strm = &(state->strm);
 
108
    int flags;
 
109
    unsigned len;
 
110
 
 
111
    /* allocate read buffers and inflate memory */
 
112
    if (state->size == 0) {
 
113
        /* allocate buffers */
 
114
        state->in = malloc(state->want);
 
115
        state->out = malloc(state->want << 1);
 
116
        if (state->in == NULL || state->out == NULL) {
 
117
            if (state->out != NULL)
 
118
                free(state->out);
 
119
            if (state->in != NULL)
 
120
                free(state->in);
 
121
            gz_error(state, Z_MEM_ERROR, "out of memory");
 
122
            return -1;
 
123
        }
 
124
        state->size = state->want;
 
125
 
 
126
        /* allocate inflate memory */
 
127
        state->strm.zalloc = Z_NULL;
 
128
        state->strm.zfree = Z_NULL;
 
129
        state->strm.opaque = Z_NULL;
 
130
        state->strm.avail_in = 0;
 
131
        state->strm.next_in = Z_NULL;
 
132
        if (inflateInit2(&(state->strm), -15) != Z_OK) {    /* raw inflate */
 
133
            free(state->out);
 
134
            free(state->in);
 
135
            state->size = 0;
 
136
            gz_error(state, Z_MEM_ERROR, "out of memory");
 
137
            return -1;
 
138
        }
 
139
    }
 
140
 
 
141
    /* get some data in the input buffer */
 
142
    if (strm->avail_in == 0) {
 
143
        if (gz_avail(state) == -1)
 
144
            return -1;
 
145
        if (strm->avail_in == 0)
 
146
            return 0;
 
147
    }
 
148
 
 
149
    /* look for the gzip magic header bytes 31 and 139 */
 
150
    if (strm->next_in[0] == 31) {
 
151
        strm->avail_in--;
 
152
        strm->next_in++;
 
153
        if (strm->avail_in == 0 && gz_avail(state) == -1)
 
154
            return -1;
 
155
        if (strm->avail_in && strm->next_in[0] == 139) {
 
156
            /* we have a gzip header, woo hoo! */
 
157
            strm->avail_in--;
 
158
            strm->next_in++;
 
159
 
 
160
            /* skip rest of header */
 
161
            if (NEXT() != 8) {      /* compression method */
 
162
                gz_error(state, Z_DATA_ERROR, "unknown compression method");
 
163
                return -1;
 
164
            }
 
165
            flags = NEXT();
 
166
            if (flags & 0xe0) {     /* reserved flag bits */
 
167
                gz_error(state, Z_DATA_ERROR, "unknown header flags set");
 
168
                return -1;
 
169
            }
 
170
            NEXT();                 /* modification time */
 
171
            NEXT();
 
172
            NEXT();
 
173
            NEXT();
 
174
            NEXT();                 /* extra flags */
 
175
            NEXT();                 /* operating system */
 
176
            if (flags & 4) {        /* extra field */
 
177
                len = (unsigned)NEXT();
 
178
                len += (unsigned)NEXT() << 8;
 
179
                while (len--)
 
180
                    if (NEXT() < 0)
 
181
                        break;
 
182
            }
 
183
            if (flags & 8)          /* file name */
 
184
                while (NEXT() > 0)
 
185
                    ;
 
186
            if (flags & 16)         /* comment */
 
187
                while (NEXT() > 0)
 
188
                    ;
 
189
            if (flags & 2) {        /* header crc */
 
190
                NEXT();
 
191
                NEXT();
 
192
            }
 
193
            /* an unexpected end of file is not checked for here -- it will be
 
194
               noticed on the first request for uncompressed data */
 
195
 
 
196
            /* set up for decompression */
 
197
            inflateReset(strm);
 
198
            strm->adler = crc32(0L, Z_NULL, 0);
 
199
            state->how = GZIP;
 
200
            state->direct = 0;
 
201
            return 0;
 
202
        }
 
203
        else {
 
204
            /* not a gzip file -- save first byte (31) and fall to raw i/o */
 
205
            state->out[0] = 31;
 
206
            state->have = 1;
 
207
        }
 
208
    }
 
209
 
 
210
    /* doing raw i/o, save start of raw data for seeking, copy any leftover
 
211
       input to output -- this assumes that the output buffer is larger than
 
212
       the input buffer, which also assures space for gzungetc() */
 
213
    state->raw = state->pos;
 
214
    state->next = state->out;
 
215
    if (strm->avail_in) {
 
216
        memcpy(state->next + state->have, strm->next_in, strm->avail_in);
 
217
        state->have += strm->avail_in;
 
218
        strm->avail_in = 0;
 
219
    }
 
220
    state->how = COPY;
 
221
    state->direct = 1;
 
222
    return 0;
 
223
}
 
224
 
 
225
/* Decompress from input to the provided next_out and avail_out in the state.
 
226
   If the end of the compressed data is reached, then verify the gzip trailer
 
227
   check value and length (modulo 2^32).  state->have and state->next are set
 
228
   to point to the just decompressed data, and the crc is updated.  If the
 
229
   trailer is verified, state->how is reset to LOOK to look for the next gzip
 
230
   stream or raw data, once state->have is depleted.  Returns 0 on success, -1
 
231
   on failure.  Failures may include invalid compressed data or a failed gzip
 
232
   trailer verification. */
 
233
local int gz_decomp(state)
 
234
    gz_statep state;
 
235
{
 
236
    int ret;
 
237
    unsigned had;
 
238
    unsigned long crc, len;
 
239
    z_streamp strm = &(state->strm);
 
240
 
 
241
    /* fill output buffer up to end of deflate stream */
 
242
    had = strm->avail_out;
 
243
    do {
 
244
        /* get more input for inflate() */
 
245
        if (strm->avail_in == 0 && gz_avail(state) == -1)
 
246
            return -1;
 
247
        if (strm->avail_in == 0) {
 
248
            gz_error(state, Z_DATA_ERROR, "unexpected end of file");
 
249
            return -1;
 
250
        }
 
251
 
 
252
        /* decompress and handle errors */
 
253
        ret = inflate(strm, Z_NO_FLUSH);
 
254
        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
 
255
            gz_error(state, Z_STREAM_ERROR,
 
256
                      "internal error: inflate stream corrupt");
 
257
            return -1;
 
258
        }
 
259
        if (ret == Z_MEM_ERROR) {
 
260
            gz_error(state, Z_MEM_ERROR, "out of memory");
 
261
            return -1;
 
262
        }
 
263
        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
 
264
            gz_error(state, Z_DATA_ERROR,
 
265
                      strm->msg == NULL ? "compressed data error" : strm->msg);
 
266
            return -1;
 
267
        }
 
268
    } while (strm->avail_out && ret != Z_STREAM_END);
 
269
 
 
270
    /* update available output and crc check value */
 
271
    state->have = had - strm->avail_out;
 
272
    state->next = strm->next_out - state->have;
 
273
    strm->adler = crc32(strm->adler, state->next, state->have);
 
274
 
 
275
    /* check gzip trailer if at end of deflate stream */
 
276
    if (ret == Z_STREAM_END) {
 
277
        if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) {
 
278
            gz_error(state, Z_DATA_ERROR, "unexpected end of file");
 
279
            return -1;
 
280
        }
 
281
        if (crc != strm->adler) {
 
282
            gz_error(state, Z_DATA_ERROR, "incorrect data check");
 
283
            return -1;
 
284
        }
 
285
        if (len != (strm->total_out & 0xffffffffL)) {
 
286
            gz_error(state, Z_DATA_ERROR, "incorrect length check");
 
287
            return -1;
 
288
        }
 
289
        state->how = LOOK;      /* ready for next stream, once have is 0 (leave
 
290
                                   state->direct unchanged to remember how) */
 
291
    }
 
292
 
 
293
    /* good decompression */
 
294
    return 0;
 
295
}
 
296
 
 
297
/* Make data and put in the output buffer.  Assumes that state->have == 0.
 
298
   Data is either copied from the input file or decompressed from the input
 
299
   file depending on state->how.  If state->how is LOOK, then a gzip header is
 
300
   looked for (and skipped if found) to determine wither to copy or decompress.
 
301
   Returns -1 on error, otherwise 0.  gz_make() will leave state->have as COPY
 
302
   or GZIP unless the end of the input file has been reached and all data has
 
303
   been processed.  */
 
304
local int gz_make(state)
 
305
    gz_statep state;
 
306
{
 
307
    z_streamp strm = &(state->strm);
 
308
 
 
309
    if (state->how == LOOK) {           /* look for gzip header */
 
310
        if (gz_head(state) == -1)
 
311
            return -1;
 
312
        if (state->have)                /* got some data from gz_head() */
 
313
            return 0;
 
314
    }
 
315
    if (state->how == COPY) {           /* straight copy */
 
316
        if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1)
 
317
            return -1;
 
318
        state->next = state->out;
 
319
    }
 
320
    else if (state->how == GZIP) {      /* decompress */
 
321
        strm->avail_out = state->size << 1;
 
322
        strm->next_out = state->out;
 
323
        if (gz_decomp(state) == -1)
 
324
            return -1;
 
325
    }
 
326
    return 0;
 
327
}
 
328
 
 
329
/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
 
330
local int gz_skip(state, len)
 
331
    gz_statep state;
 
332
    z_off64_t len;
 
333
{
 
334
    unsigned n;
 
335
 
 
336
    /* skip over len bytes or reach end-of-file, whichever comes first */
 
337
    while (len)
 
338
        /* skip over whatever is in output buffer */
 
339
        if (state->have) {
 
340
            n = GT_OFF(state->have) || (z_off64_t)state->have > len ?
 
341
                (unsigned)len : state->have;
 
342
            state->have -= n;
 
343
            state->next += n;
 
344
            state->pos += n;
 
345
            len -= n;
 
346
        }
 
347
 
 
348
        /* output buffer empty -- return if we're at the end of the input */
 
349
        else if (state->eof && state->strm.avail_in == 0)
 
350
            break;
 
351
 
 
352
        /* need more data to skip -- load up output buffer */
 
353
        else {
 
354
            /* get more output, looking for header if required */
 
355
            if (gz_make(state) == -1)
 
356
                return -1;
 
357
        }
 
358
    return 0;
 
359
}
 
360
 
 
361
/* -- see zlib.h -- */
 
362
int ZEXPORT gzread(file, buf, len)
 
363
    gzFile file;
 
364
    voidp buf;
 
365
    unsigned len;
 
366
{
 
367
    unsigned got, n;
 
368
    gz_statep state;
 
369
    z_streamp strm;
 
370
 
 
371
    /* get internal structure */
 
372
    if (file == NULL)
 
373
        return -1;
 
374
    state = (gz_statep)file;
 
375
    strm = &(state->strm);
 
376
 
 
377
    /* check that we're reading and that there's no error */
 
378
    if (state->mode != GZ_READ || state->err != Z_OK)
 
379
        return -1;
 
380
 
 
381
    /* since an int is returned, make sure len fits in one, otherwise return
 
382
       with an error (this avoids the flaw in the interface) */
 
383
    if ((int)len < 0) {
 
384
        gz_error(state, Z_BUF_ERROR, "requested length does not fit in int");
 
385
        return -1;
 
386
    }
 
387
 
 
388
    /* if len is zero, avoid unnecessary operations */
 
389
    if (len == 0)
 
390
        return 0;
 
391
 
 
392
    /* process a skip request */
 
393
    if (state->seek) {
 
394
        state->seek = 0;
 
395
        if (gz_skip(state, state->skip) == -1)
 
396
            return -1;
 
397
    }
 
398
 
 
399
    /* get len bytes to buf, or less than len if at the end */
 
400
    got = 0;
 
401
    do {
 
402
        /* first just try copying data from the output buffer */
 
403
        if (state->have) {
 
404
            n = state->have > len ? len : state->have;
 
405
            memcpy(buf, state->next, n);
 
406
            state->next += n;
 
407
            state->have -= n;
 
408
        }
 
409
 
 
410
        /* output buffer empty -- return if we're at the end of the input */
 
411
        else if (state->eof && strm->avail_in == 0)
 
412
            break;
 
413
 
 
414
        /* need output data -- for small len or new stream load up our output
 
415
           buffer */
 
416
        else if (state->how == LOOK || len < (state->size << 1)) {
 
417
            /* get more output, looking for header if required */
 
418
            if (gz_make(state) == -1)
 
419
                return -1;
 
420
            continue;       /* no progress yet -- go back to memcpy() above */
 
421
            /* the copy above assures that we will leave with space in the
 
422
               output buffer, allowing at least one gzungetc() to succeed */
 
423
        }
 
424
 
 
425
        /* large len -- read directly into user buffer */
 
426
        else if (state->how == COPY) {      /* read directly */
 
427
            if (gz_load(state, buf, len, &n) == -1)
 
428
                return -1;
 
429
        }
 
430
 
 
431
        /* large len -- decompress directly into user buffer */
 
432
        else {  /* state->how == GZIP */
 
433
            strm->avail_out = len;
 
434
            strm->next_out = buf;
 
435
            if (gz_decomp(state) == -1)
 
436
                return -1;
 
437
            n = state->have;
 
438
            state->have = 0;
 
439
        }
 
440
 
 
441
        /* update progress */
 
442
        len -= n;
 
443
        buf = (char *)buf + n;
 
444
        got += n;
 
445
        state->pos += n;
 
446
    } while (len);
 
447
 
 
448
    /* return number of bytes read into user buffer (will fit in int) */
 
449
    return (int)got;
 
450
}
 
451
 
 
452
/* -- see zlib.h -- */
 
453
int ZEXPORT gzgetc(file)
 
454
    gzFile file;
 
455
{
 
456
    int ret;
 
457
    unsigned char buf[1];
 
458
    gz_statep state;
 
459
 
 
460
    /* get internal structure */
 
461
    if (file == NULL)
 
462
        return -1;
 
463
    state = (gz_statep)file;
 
464
 
 
465
    /* check that we're reading and that there's no error */
 
466
    if (state->mode != GZ_READ || state->err != Z_OK)
 
467
        return -1;
 
468
 
 
469
    /* try output buffer (no need to check for skip request) */
 
470
    if (state->have) {
 
471
        state->have--;
 
472
        state->pos++;
 
473
        return *(state->next)++;
 
474
    }
 
475
 
 
476
    /* nothing there -- try gzread() */
 
477
    ret = gzread(file, buf, 1);
 
478
    return ret < 1 ? -1 : buf[0];
 
479
}
 
480
 
 
481
/* -- see zlib.h -- */
 
482
int ZEXPORT gzungetc(c, file)
 
483
    int c;
 
484
    gzFile file;
 
485
{
 
486
    gz_statep state;
 
487
 
 
488
    /* get internal structure */
 
489
    if (file == NULL)
 
490
        return -1;
 
491
    state = (gz_statep)file;
 
492
 
 
493
    /* check that we're reading and that there's no error */
 
494
    if (state->mode != GZ_READ || state->err != Z_OK)
 
495
        return -1;
 
496
 
 
497
    /* process a skip request */
 
498
    if (state->seek) {
 
499
        state->seek = 0;
 
500
        if (gz_skip(state, state->skip) == -1)
 
501
            return -1;
 
502
    }
 
503
 
 
504
    /* can't push EOF */
 
505
    if (c < 0)
 
506
        return -1;
 
507
 
 
508
    /* if output buffer empty, put byte at end (allows more pushing) */
 
509
    if (state->have == 0) {
 
510
        state->have = 1;
 
511
        state->next = state->out + (state->size << 1) - 1;
 
512
        state->next[0] = c;
 
513
        state->pos--;
 
514
        return c;
 
515
    }
 
516
 
 
517
    /* if no room, give up (must have already done a gzungetc()) */
 
518
    if (state->have == (state->size << 1)) {
 
519
        gz_error(state, Z_BUF_ERROR, "out of room to push characters");
 
520
        return -1;
 
521
    }
 
522
 
 
523
    /* slide output data if needed and insert byte before existing data */
 
524
    if (state->next == state->out) {
 
525
        unsigned char *src = state->out + state->have;
 
526
        unsigned char *dest = state->out + (state->size << 1);
 
527
        while (src > state->out)
 
528
            *--dest = *--src;
 
529
        state->next = dest;
 
530
    }
 
531
    state->have++;
 
532
    state->next--;
 
533
    state->next[0] = c;
 
534
    state->pos--;
 
535
    return c;
 
536
}
 
537
 
 
538
/* -- see zlib.h -- */
 
539
char * ZEXPORT gzgets(file, buf, len)
 
540
    gzFile file;
 
541
    char *buf;
 
542
    int len;
 
543
{
 
544
    unsigned left, n;
 
545
    char *str;
 
546
    unsigned char *eol;
 
547
    gz_statep state;
 
548
 
 
549
    /* check parameters and get internal structure */
 
550
    if (file == NULL || buf == NULL || len < 1)
 
551
        return NULL;
 
552
    state = (gz_statep)file;
 
553
 
 
554
    /* check that we're reading and that there's no error */
 
555
    if (state->mode != GZ_READ || state->err != Z_OK)
 
556
        return NULL;
 
557
 
 
558
    /* process a skip request */
 
559
    if (state->seek) {
 
560
        state->seek = 0;
 
561
        if (gz_skip(state, state->skip) == -1)
 
562
            return NULL;
 
563
    }
 
564
 
 
565
    /* copy output bytes up to new line or len - 1, whichever comes first --
 
566
       append a terminating zero to the string (we don't check for a zero in
 
567
       the contents, let the user worry about that) */
 
568
    str = buf;
 
569
    left = (unsigned)len - 1;
 
570
    if (left) do {
 
571
        /* assure that something is in the output buffer */
 
572
        if (state->have == 0) {
 
573
            if (gz_make(state) == -1)
 
574
                return NULL;            /* error */
 
575
            if (state->have == 0) {     /* end of file */
 
576
                if (buf == str)         /* got bupkus */
 
577
                    return NULL;
 
578
                break;                  /* got something -- return it */
 
579
            }
 
580
        }
 
581
 
 
582
        /* look for end-of-line in current output buffer */
 
583
        n = state->have > left ? left : state->have;
 
584
        eol = memchr(state->next, '\n', n);
 
585
        if (eol != NULL)
 
586
            n = (unsigned)(eol - state->next) + 1;
 
587
 
 
588
        /* copy through end-of-line, or remainder if not found */
 
589
        memcpy(buf, state->next, n);
 
590
        state->have -= n;
 
591
        state->next += n;
 
592
        state->pos += n;
 
593
        left -= n;
 
594
        buf += n;
 
595
    } while (left && eol == NULL);
 
596
 
 
597
    /* found end-of-line or out of space -- terminate string and return it */
 
598
    buf[0] = 0;
 
599
    return str;
 
600
}
 
601
 
 
602
/* -- see zlib.h -- */
 
603
int ZEXPORT gzdirect(file)
 
604
    gzFile file;
 
605
{
 
606
    gz_statep state;
 
607
 
 
608
    /* get internal structure */
 
609
    if (file == NULL)
 
610
        return 0;
 
611
    state = (gz_statep)file;
 
612
 
 
613
    /* check that we're reading */
 
614
    if (state->mode != GZ_READ)
 
615
        return 0;
 
616
 
 
617
    /* if the state is not known, but we can find out, then do so (this is
 
618
       mainly for right after a gzopen() or gzdopen()) */
 
619
    if (state->how == LOOK && state->have == 0)
 
620
        (void)gz_head(state);
 
621
 
 
622
    /* return 1 if reading direct, 0 if decompressing a gzip stream */
 
623
    return state->direct;
 
624
}
 
625
 
 
626
/* -- see zlib.h -- */
 
627
int ZEXPORT gzclose_r(file)
 
628
    gzFile file;
 
629
{
 
630
    int ret;
 
631
    gz_statep state;
 
632
 
 
633
    /* get internal structure */
 
634
    if (file == NULL)
 
635
        return Z_STREAM_ERROR;
 
636
    state = (gz_statep)file;
 
637
 
 
638
    /* check that we're reading */
 
639
    if (state->mode != GZ_READ)
 
640
        return Z_STREAM_ERROR;
 
641
 
 
642
    /* free memory and close file */
 
643
    if (state->size) {
 
644
        inflateEnd(&(state->strm));
 
645
        free(state->out);
 
646
        free(state->in);
 
647
    }
 
648
    gz_error(state, Z_OK, NULL);
 
649
    free(state->path);
 
650
    ret = close(state->fd);
 
651
    free(state);
 
652
    return ret ? Z_ERRNO : Z_OK;
 
653
}