1275793eaSopenharmony_ci/* gzread.c -- zlib functions for reading gzip files
2275793eaSopenharmony_ci * Copyright (C) 2004-2017 Mark Adler
3275793eaSopenharmony_ci * For conditions of distribution and use, see copyright notice in zlib.h
4275793eaSopenharmony_ci */
5275793eaSopenharmony_ci
6275793eaSopenharmony_ci#include "gzguts.h"
7275793eaSopenharmony_ci#include <fcntl.h>
8275793eaSopenharmony_ci#include <unistd.h>
9275793eaSopenharmony_ci
10275793eaSopenharmony_ci/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
11275793eaSopenharmony_ci   state->fd, and update state->eof, state->err, and state->msg as appropriate.
12275793eaSopenharmony_ci   This function needs to loop on read(), since read() is not guaranteed to
13275793eaSopenharmony_ci   read the number of bytes requested, depending on the type of descriptor. */
14275793eaSopenharmony_cilocal int gz_load(gz_statep state, unsigned char *buf, unsigned len,
15275793eaSopenharmony_ci                  unsigned *have)
16275793eaSopenharmony_ci{
17275793eaSopenharmony_ci    int ret;
18275793eaSopenharmony_ci    unsigned get, max = ((unsigned)-1 >> 2) + 1;
19275793eaSopenharmony_ci
20275793eaSopenharmony_ci    *have = 0;
21275793eaSopenharmony_ci    do {
22275793eaSopenharmony_ci        get = len - *have;
23275793eaSopenharmony_ci        if (get > max)
24275793eaSopenharmony_ci        {
25275793eaSopenharmony_ci            get = max;
26275793eaSopenharmony_ci        }
27275793eaSopenharmony_ci        ret = read(state->fd, buf + *have, get);
28275793eaSopenharmony_ci        if (ret <= 0)
29275793eaSopenharmony_ci        {
30275793eaSopenharmony_ci            break;
31275793eaSopenharmony_ci        }
32275793eaSopenharmony_ci        *have += (unsigned)ret;
33275793eaSopenharmony_ci    } while (*have < len);
34275793eaSopenharmony_ci    if (ret < 0) {
35275793eaSopenharmony_ci        gz_error(state, Z_ERRNO, zstrerror());
36275793eaSopenharmony_ci        return -1;
37275793eaSopenharmony_ci    }
38275793eaSopenharmony_ci    if (ret == 0)
39275793eaSopenharmony_ci    {
40275793eaSopenharmony_ci        state->eof = 1;
41275793eaSopenharmony_ci    }
42275793eaSopenharmony_ci    return 0;
43275793eaSopenharmony_ci}
44275793eaSopenharmony_ci
45275793eaSopenharmony_ci/* Load up input buffer and set eof flag if last data loaded -- return -1 on
46275793eaSopenharmony_ci   error, 0 otherwise.  Note that the eof flag is set when the end of the input
47275793eaSopenharmony_ci   file is reached, even though there may be unused data in the buffer.  Once
48275793eaSopenharmony_ci   that data has been used, no more attempts will be made to read the file.
49275793eaSopenharmony_ci   If strm->avail_in != 0, then the current data is moved to the beginning of
50275793eaSopenharmony_ci   the input buffer, and then the remainder of the buffer is loaded with the
51275793eaSopenharmony_ci   available data from the input file. */
52275793eaSopenharmony_cilocal int gz_avail(gz_statep state)
53275793eaSopenharmony_ci{
54275793eaSopenharmony_ci    unsigned got;
55275793eaSopenharmony_ci    z_streamp strm = &(state->strm);
56275793eaSopenharmony_ci
57275793eaSopenharmony_ci    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
58275793eaSopenharmony_ci    {
59275793eaSopenharmony_ci        return -1;
60275793eaSopenharmony_ci    }
61275793eaSopenharmony_ci    if (state->eof == 0) {
62275793eaSopenharmony_ci        if (strm->avail_in) {       /* copy what's there to the start */
63275793eaSopenharmony_ci            unsigned char *p = state->in;
64275793eaSopenharmony_ci            unsigned const char *q = strm->next_in;
65275793eaSopenharmony_ci            unsigned n = strm->avail_in;
66275793eaSopenharmony_ci            do {
67275793eaSopenharmony_ci                *p++ = *q++;
68275793eaSopenharmony_ci            } while (--n);
69275793eaSopenharmony_ci        }
70275793eaSopenharmony_ci        if (gz_load(state, state->in + strm->avail_in,
71275793eaSopenharmony_ci                    state->size - strm->avail_in, &got) == -1)
72275793eaSopenharmony_ci        {
73275793eaSopenharmony_ci            return -1;
74275793eaSopenharmony_ci        }
75275793eaSopenharmony_ci        strm->avail_in += got;
76275793eaSopenharmony_ci        strm->next_in = state->in;
77275793eaSopenharmony_ci    }
78275793eaSopenharmony_ci    return 0;
79275793eaSopenharmony_ci}
80275793eaSopenharmony_ci
81275793eaSopenharmony_ci/* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.
82275793eaSopenharmony_ci   If this is the first time in, allocate required memory.  state->how will be
83275793eaSopenharmony_ci   left unchanged if there is no more input data available, will be set to COPY
84275793eaSopenharmony_ci   if there is no gzip header and direct copying will be performed, or it will
85275793eaSopenharmony_ci   be set to GZIP for decompression.  If direct copying, then leftover input
86275793eaSopenharmony_ci   data from the input buffer will be copied to the output buffer.  In that
87275793eaSopenharmony_ci   case, all further file reads will be directly to either the output buffer or
88275793eaSopenharmony_ci   a user buffer.  If decompressing, the inflate state will be initialized.
89275793eaSopenharmony_ci   gz_look() will return 0 on success or -1 on failure. */
90275793eaSopenharmony_cilocal int gz_look(gz_statep state)
91275793eaSopenharmony_ci{
92275793eaSopenharmony_ci    z_streamp strm = &(state->strm);
93275793eaSopenharmony_ci
94275793eaSopenharmony_ci    /* allocate read buffers and inflate memory */
95275793eaSopenharmony_ci    if (state->size == 0) {
96275793eaSopenharmony_ci        /* allocate buffers */
97275793eaSopenharmony_ci        state->in = (unsigned char *)malloc(state->want);
98275793eaSopenharmony_ci        state->out = (unsigned char *)malloc(state->want << 1);
99275793eaSopenharmony_ci        if (state->in == NULL || state->out == NULL) {
100275793eaSopenharmony_ci            free(state->out);
101275793eaSopenharmony_ci            free(state->in);
102275793eaSopenharmony_ci            gz_error(state, Z_MEM_ERROR, "out of memory");
103275793eaSopenharmony_ci            return -1;
104275793eaSopenharmony_ci        }
105275793eaSopenharmony_ci        state->size = state->want;
106275793eaSopenharmony_ci
107275793eaSopenharmony_ci        /* allocate inflate memory */
108275793eaSopenharmony_ci        state->strm.zalloc = Z_NULL;
109275793eaSopenharmony_ci        state->strm.zfree = Z_NULL;
110275793eaSopenharmony_ci        state->strm.opaque = Z_NULL;
111275793eaSopenharmony_ci        state->strm.avail_in = 0;
112275793eaSopenharmony_ci        state->strm.next_in = Z_NULL;
113275793eaSopenharmony_ci        if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) {    /* gunzip */
114275793eaSopenharmony_ci            free(state->out);
115275793eaSopenharmony_ci            free(state->in);
116275793eaSopenharmony_ci            state->size = 0;
117275793eaSopenharmony_ci            gz_error(state, Z_MEM_ERROR, "out of memory");
118275793eaSopenharmony_ci            return -1;
119275793eaSopenharmony_ci        }
120275793eaSopenharmony_ci    }
121275793eaSopenharmony_ci
122275793eaSopenharmony_ci    /* get at least the magic bytes in the input buffer */
123275793eaSopenharmony_ci    if (strm->avail_in < 2) {
124275793eaSopenharmony_ci        if (gz_avail(state) == -1)
125275793eaSopenharmony_ci        {
126275793eaSopenharmony_ci            return -1;
127275793eaSopenharmony_ci        }
128275793eaSopenharmony_ci        if (strm->avail_in == 0)
129275793eaSopenharmony_ci        {
130275793eaSopenharmony_ci            return 0;
131275793eaSopenharmony_ci        }
132275793eaSopenharmony_ci    }
133275793eaSopenharmony_ci
134275793eaSopenharmony_ci    /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
135275793eaSopenharmony_ci       a logical dilemma here when considering the case of a partially written
136275793eaSopenharmony_ci       gzip file, to wit, if a single 31 byte is written, then we cannot tell
137275793eaSopenharmony_ci       whether this is a single-byte file, or just a partially written gzip
138275793eaSopenharmony_ci       file -- for here we assume that if a gzip file is being written, then
139275793eaSopenharmony_ci       the header will be written in a single operation, so that reading a
140275793eaSopenharmony_ci       single byte is sufficient indication that it is not a gzip file) */
141275793eaSopenharmony_ci    if (strm->avail_in > 1 &&
142275793eaSopenharmony_ci            strm->next_in[0] == 31 && strm->next_in[1] == 139) {
143275793eaSopenharmony_ci        inflateReset(strm);
144275793eaSopenharmony_ci        state->how = GZIP;
145275793eaSopenharmony_ci        state->direct = 0;
146275793eaSopenharmony_ci        return 0;
147275793eaSopenharmony_ci    }
148275793eaSopenharmony_ci
149275793eaSopenharmony_ci    /* no gzip header -- if we were decoding gzip before, then this is trailing
150275793eaSopenharmony_ci       garbage.  Ignore the trailing garbage and finish. */
151275793eaSopenharmony_ci    if (state->direct == 0) {
152275793eaSopenharmony_ci        strm->avail_in = 0;
153275793eaSopenharmony_ci        state->eof = 1;
154275793eaSopenharmony_ci        state->x.have = 0;
155275793eaSopenharmony_ci        return 0;
156275793eaSopenharmony_ci    }
157275793eaSopenharmony_ci
158275793eaSopenharmony_ci    /* doing raw i/o, copy any leftover input to output -- this assumes that
159275793eaSopenharmony_ci       the output buffer is larger than the input buffer, which also assures
160275793eaSopenharmony_ci       space for gzungetc() */
161275793eaSopenharmony_ci    state->x.next = state->out;
162275793eaSopenharmony_ci    memcpy(state->x.next, strm->next_in, strm->avail_in);
163275793eaSopenharmony_ci    state->x.have = strm->avail_in;
164275793eaSopenharmony_ci    strm->avail_in = 0;
165275793eaSopenharmony_ci    state->how = COPY;
166275793eaSopenharmony_ci    state->direct = 1;
167275793eaSopenharmony_ci    return 0;
168275793eaSopenharmony_ci}
169275793eaSopenharmony_ci
170275793eaSopenharmony_ci/* Decompress from input to the provided next_out and avail_out in the state.
171275793eaSopenharmony_ci   On return, state->x.have and state->x.next point to the just decompressed
172275793eaSopenharmony_ci   data.  If the gzip stream completes, state->how is reset to LOOK to look for
173275793eaSopenharmony_ci   the next gzip stream or raw data, once state->x.have is depleted.  Returns 0
174275793eaSopenharmony_ci   on success, -1 on failure. */
175275793eaSopenharmony_cilocal int gz_decomp(gz_statep state)
176275793eaSopenharmony_ci{
177275793eaSopenharmony_ci    int ret = Z_OK;
178275793eaSopenharmony_ci    unsigned had;
179275793eaSopenharmony_ci    z_streamp strm = &(state->strm);
180275793eaSopenharmony_ci
181275793eaSopenharmony_ci    /* fill output buffer up to end of deflate stream */
182275793eaSopenharmony_ci    had = strm->avail_out;
183275793eaSopenharmony_ci    do {
184275793eaSopenharmony_ci        /* get more input for inflate() */
185275793eaSopenharmony_ci        if (strm->avail_in == 0 && gz_avail(state) == -1)
186275793eaSopenharmony_ci        {
187275793eaSopenharmony_ci            return -1;
188275793eaSopenharmony_ci        }
189275793eaSopenharmony_ci        if (strm->avail_in == 0) {
190275793eaSopenharmony_ci            gz_error(state, Z_BUF_ERROR, "unexpected end of file");
191275793eaSopenharmony_ci            break;
192275793eaSopenharmony_ci        }
193275793eaSopenharmony_ci
194275793eaSopenharmony_ci        /* decompress and handle errors */
195275793eaSopenharmony_ci        ret = inflate(strm, Z_NO_FLUSH);
196275793eaSopenharmony_ci        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
197275793eaSopenharmony_ci            gz_error(state, Z_STREAM_ERROR,
198275793eaSopenharmony_ci                     "internal error: inflate stream corrupt");
199275793eaSopenharmony_ci            return -1;
200275793eaSopenharmony_ci        }
201275793eaSopenharmony_ci        if (ret == Z_MEM_ERROR) {
202275793eaSopenharmony_ci            gz_error(state, Z_MEM_ERROR, "out of memory");
203275793eaSopenharmony_ci            return -1;
204275793eaSopenharmony_ci        }
205275793eaSopenharmony_ci        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
206275793eaSopenharmony_ci            gz_error(state, Z_DATA_ERROR,
207275793eaSopenharmony_ci                     strm->msg == NULL ? "compressed data error" : strm->msg);
208275793eaSopenharmony_ci            return -1;
209275793eaSopenharmony_ci        }
210275793eaSopenharmony_ci    } while (strm->avail_out && ret != Z_STREAM_END);
211275793eaSopenharmony_ci
212275793eaSopenharmony_ci    /* update available output */
213275793eaSopenharmony_ci    state->x.have = had - strm->avail_out;
214275793eaSopenharmony_ci    state->x.next = strm->next_out - state->x.have;
215275793eaSopenharmony_ci
216275793eaSopenharmony_ci    /* if the gzip stream completed successfully, look for another */
217275793eaSopenharmony_ci    if (ret == Z_STREAM_END)
218275793eaSopenharmony_ci        state->how = LOOK;
219275793eaSopenharmony_ci
220275793eaSopenharmony_ci    /* good decompression */
221275793eaSopenharmony_ci    return 0;
222275793eaSopenharmony_ci}
223275793eaSopenharmony_ci
224275793eaSopenharmony_ci/* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.
225275793eaSopenharmony_ci   Data is either copied from the input file or decompressed from the input
226275793eaSopenharmony_ci   file depending on state->how.  If state->how is LOOK, then a gzip header is
227275793eaSopenharmony_ci   looked for to determine whether to copy or decompress.  Returns -1 on error,
228275793eaSopenharmony_ci   otherwise 0.  gz_fetch() will leave state->how as COPY or GZIP unless the
229275793eaSopenharmony_ci   end of the input file has been reached and all data has been processed.  */
230275793eaSopenharmony_cilocal int gz_fetch(gz_statep state)
231275793eaSopenharmony_ci{
232275793eaSopenharmony_ci    z_streamp strm = &(state->strm);
233275793eaSopenharmony_ci
234275793eaSopenharmony_ci    do {
235275793eaSopenharmony_ci        switch(state->how) {
236275793eaSopenharmony_ci        case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
237275793eaSopenharmony_ci            if (gz_look(state) == -1)
238275793eaSopenharmony_ci            {
239275793eaSopenharmony_ci                return -1;
240275793eaSopenharmony_ci            }
241275793eaSopenharmony_ci            if (state->how == LOOK)
242275793eaSopenharmony_ci            {
243275793eaSopenharmony_ci                return 0;
244275793eaSopenharmony_ci            }
245275793eaSopenharmony_ci            break;
246275793eaSopenharmony_ci        case COPY:      /* -> COPY */
247275793eaSopenharmony_ci            if (gz_load(state, state->out, state->size << 1, &(state->x.have))
248275793eaSopenharmony_ci                    == -1)
249275793eaSopenharmony_ci            {
250275793eaSopenharmony_ci                return -1;
251275793eaSopenharmony_ci            }
252275793eaSopenharmony_ci            state->x.next = state->out;
253275793eaSopenharmony_ci            return 0;
254275793eaSopenharmony_ci        case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
255275793eaSopenharmony_ci            strm->avail_out = state->size << 1;
256275793eaSopenharmony_ci            strm->next_out = state->out;
257275793eaSopenharmony_ci            if (gz_decomp(state) == -1)
258275793eaSopenharmony_ci            {
259275793eaSopenharmony_ci                return -1;
260275793eaSopenharmony_ci            }
261275793eaSopenharmony_ci        }
262275793eaSopenharmony_ci    } while (state->x.have == 0 && (!state->eof || strm->avail_in));
263275793eaSopenharmony_ci    return 0;
264275793eaSopenharmony_ci}
265275793eaSopenharmony_ci
266275793eaSopenharmony_ci/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
267275793eaSopenharmony_cilocal int gz_skip(gz_statep state, z_off64_t len)
268275793eaSopenharmony_ci{
269275793eaSopenharmony_ci    unsigned n;
270275793eaSopenharmony_ci
271275793eaSopenharmony_ci    /* skip over len bytes or reach end-of-file, whichever comes first */
272275793eaSopenharmony_ci    while (len)
273275793eaSopenharmony_ci        /* skip over whatever is in output buffer */
274275793eaSopenharmony_ci        if (state->x.have) {
275275793eaSopenharmony_ci            n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
276275793eaSopenharmony_ci                (unsigned)len : state->x.have;
277275793eaSopenharmony_ci            state->x.have -= n;
278275793eaSopenharmony_ci            state->x.next += n;
279275793eaSopenharmony_ci            state->x.pos += n;
280275793eaSopenharmony_ci            len -= n;
281275793eaSopenharmony_ci        }
282275793eaSopenharmony_ci
283275793eaSopenharmony_ci        /* output buffer empty -- return if we're at the end of the input */
284275793eaSopenharmony_ci        else if (state->eof && state->strm.avail_in == 0)
285275793eaSopenharmony_ci        {
286275793eaSopenharmony_ci            break;
287275793eaSopenharmony_ci        }
288275793eaSopenharmony_ci
289275793eaSopenharmony_ci        /* need more data to skip -- load up output buffer */
290275793eaSopenharmony_ci        else {
291275793eaSopenharmony_ci            /* get more output, looking for header if required */
292275793eaSopenharmony_ci            if (gz_fetch(state) == -1)
293275793eaSopenharmony_ci            {
294275793eaSopenharmony_ci                return -1;
295275793eaSopenharmony_ci            }
296275793eaSopenharmony_ci        }
297275793eaSopenharmony_ci    return 0;
298275793eaSopenharmony_ci}
299275793eaSopenharmony_ci
300275793eaSopenharmony_ci/* Read len bytes into buf from file, or less than len up to the end of the
301275793eaSopenharmony_ci   input.  Return the number of bytes read.  If zero is returned, either the
302275793eaSopenharmony_ci   end of file was reached, or there was an error.  state->err must be
303275793eaSopenharmony_ci   consulted in that case to determine which. */
304275793eaSopenharmony_cilocal z_size_t gz_read(gz_statep state, voidp buf, z_size_t len)
305275793eaSopenharmony_ci{
306275793eaSopenharmony_ci    z_size_t got;
307275793eaSopenharmony_ci    unsigned n;
308275793eaSopenharmony_ci
309275793eaSopenharmony_ci    /* if len is zero, avoid unnecessary operations */
310275793eaSopenharmony_ci    if (len == 0)
311275793eaSopenharmony_ci    {
312275793eaSopenharmony_ci        return 0;
313275793eaSopenharmony_ci    }
314275793eaSopenharmony_ci
315275793eaSopenharmony_ci    /* process a skip request */
316275793eaSopenharmony_ci    if (state->seek) {
317275793eaSopenharmony_ci        state->seek = 0;
318275793eaSopenharmony_ci        if (gz_skip(state, state->skip) == -1)
319275793eaSopenharmony_ci        {
320275793eaSopenharmony_ci            return 0;
321275793eaSopenharmony_ci        }
322275793eaSopenharmony_ci    }
323275793eaSopenharmony_ci
324275793eaSopenharmony_ci    /* get len bytes to buf, or less than len if at the end */
325275793eaSopenharmony_ci    got = 0;
326275793eaSopenharmony_ci    do {
327275793eaSopenharmony_ci        /* set n to the maximum amount of len that fits in an unsigned int */
328275793eaSopenharmony_ci        n = (unsigned)-1;
329275793eaSopenharmony_ci        if (n > len)
330275793eaSopenharmony_ci        {
331275793eaSopenharmony_ci            n = (unsigned)len;
332275793eaSopenharmony_ci        }
333275793eaSopenharmony_ci
334275793eaSopenharmony_ci        /* first just try copying data from the output buffer */
335275793eaSopenharmony_ci        if (state->x.have) {
336275793eaSopenharmony_ci            if (state->x.have < n)
337275793eaSopenharmony_ci            {
338275793eaSopenharmony_ci                n = state->x.have;
339275793eaSopenharmony_ci            }
340275793eaSopenharmony_ci            memcpy(buf, state->x.next, n);
341275793eaSopenharmony_ci            state->x.next += n;
342275793eaSopenharmony_ci            state->x.have -= n;
343275793eaSopenharmony_ci        }
344275793eaSopenharmony_ci
345275793eaSopenharmony_ci        /* output buffer empty -- return if we're at the end of the input */
346275793eaSopenharmony_ci        else if (state->eof && state->strm.avail_in == 0) {
347275793eaSopenharmony_ci            state->past = 1;        /* tried to read past end */
348275793eaSopenharmony_ci            break;
349275793eaSopenharmony_ci        }
350275793eaSopenharmony_ci
351275793eaSopenharmony_ci        /* need output data -- for small len or new stream load up our output
352275793eaSopenharmony_ci           buffer */
353275793eaSopenharmony_ci        else if (state->how == LOOK || n < (state->size << 1)) {
354275793eaSopenharmony_ci            /* get more output, looking for header if required */
355275793eaSopenharmony_ci            if (gz_fetch(state) == -1)
356275793eaSopenharmony_ci            {
357275793eaSopenharmony_ci                return 0;
358275793eaSopenharmony_ci            }
359275793eaSopenharmony_ci            continue;       /* no progress yet -- go back to copy above */
360275793eaSopenharmony_ci            /* the copy above assures that we will leave with space in the
361275793eaSopenharmony_ci               output buffer, allowing at least one gzungetc() to succeed */
362275793eaSopenharmony_ci        }
363275793eaSopenharmony_ci
364275793eaSopenharmony_ci        /* large len -- read directly into user buffer */
365275793eaSopenharmony_ci        else if (state->how == COPY) {      /* read directly */
366275793eaSopenharmony_ci            if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
367275793eaSopenharmony_ci            {
368275793eaSopenharmony_ci                return 0;
369275793eaSopenharmony_ci            }
370275793eaSopenharmony_ci        }
371275793eaSopenharmony_ci
372275793eaSopenharmony_ci        /* large len -- decompress directly into user buffer */
373275793eaSopenharmony_ci        else {  /* state->how == GZIP */
374275793eaSopenharmony_ci            state->strm.avail_out = n;
375275793eaSopenharmony_ci            state->strm.next_out = (unsigned char *)buf;
376275793eaSopenharmony_ci            if (gz_decomp(state) == -1)
377275793eaSopenharmony_ci            {
378275793eaSopenharmony_ci                return 0;
379275793eaSopenharmony_ci            }
380275793eaSopenharmony_ci            n = state->x.have;
381275793eaSopenharmony_ci            state->x.have = 0;
382275793eaSopenharmony_ci        }
383275793eaSopenharmony_ci
384275793eaSopenharmony_ci        /* update progress */
385275793eaSopenharmony_ci        len -= n;
386275793eaSopenharmony_ci        buf = (char *)buf + n;
387275793eaSopenharmony_ci        got += n;
388275793eaSopenharmony_ci        state->x.pos += n;
389275793eaSopenharmony_ci    } while (len);
390275793eaSopenharmony_ci
391275793eaSopenharmony_ci    /* return number of bytes read into user buffer */
392275793eaSopenharmony_ci    return got;
393275793eaSopenharmony_ci}
394275793eaSopenharmony_ci
395275793eaSopenharmony_ci/* -- see zlib.h -- */
396275793eaSopenharmony_ciint ZEXPORT gzread(gzFile file, voidp buf, unsigned len)
397275793eaSopenharmony_ci{
398275793eaSopenharmony_ci    gz_statep state;
399275793eaSopenharmony_ci
400275793eaSopenharmony_ci    /* get internal structure */
401275793eaSopenharmony_ci    if (file == NULL)
402275793eaSopenharmony_ci    {
403275793eaSopenharmony_ci        return -1;
404275793eaSopenharmony_ci    }
405275793eaSopenharmony_ci    state = (gz_statep)file;
406275793eaSopenharmony_ci
407275793eaSopenharmony_ci    /* check that we're reading and that there's no (serious) error */
408275793eaSopenharmony_ci    if (state->mode != GZ_READ ||
409275793eaSopenharmony_ci            (state->err != Z_OK && state->err != Z_BUF_ERROR))
410275793eaSopenharmony_ci    {
411275793eaSopenharmony_ci        return -1;
412275793eaSopenharmony_ci    }
413275793eaSopenharmony_ci
414275793eaSopenharmony_ci    /* since an int is returned, make sure len fits in one, otherwise return
415275793eaSopenharmony_ci       with an error (this avoids a flaw in the interface) */
416275793eaSopenharmony_ci    if ((int)len < 0) {
417275793eaSopenharmony_ci        gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");
418275793eaSopenharmony_ci        return -1;
419275793eaSopenharmony_ci    }
420275793eaSopenharmony_ci
421275793eaSopenharmony_ci    /* read len or fewer bytes to buf */
422275793eaSopenharmony_ci    len = (unsigned)gz_read(state, buf, len);
423275793eaSopenharmony_ci
424275793eaSopenharmony_ci    /* check for an error */
425275793eaSopenharmony_ci    if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
426275793eaSopenharmony_ci    {
427275793eaSopenharmony_ci        return -1;
428275793eaSopenharmony_ci    }
429275793eaSopenharmony_ci
430275793eaSopenharmony_ci    /* return the number of bytes read (this is assured to fit in an int) */
431275793eaSopenharmony_ci    return (int)len;
432275793eaSopenharmony_ci}
433275793eaSopenharmony_ci
434275793eaSopenharmony_ci/* -- see zlib.h -- */
435275793eaSopenharmony_ciz_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file)
436275793eaSopenharmony_ci{
437275793eaSopenharmony_ci    z_size_t len;
438275793eaSopenharmony_ci    gz_statep state;
439275793eaSopenharmony_ci
440275793eaSopenharmony_ci    /* get internal structure */
441275793eaSopenharmony_ci    if (file == NULL)
442275793eaSopenharmony_ci    {
443275793eaSopenharmony_ci        return 0;
444275793eaSopenharmony_ci    }
445275793eaSopenharmony_ci    state = (gz_statep)file;
446275793eaSopenharmony_ci
447275793eaSopenharmony_ci    /* check that we're reading and that there's no (serious) error */
448275793eaSopenharmony_ci    if (state->mode != GZ_READ ||
449275793eaSopenharmony_ci            (state->err != Z_OK && state->err != Z_BUF_ERROR))
450275793eaSopenharmony_ci    {
451275793eaSopenharmony_ci        return 0;
452275793eaSopenharmony_ci    }
453275793eaSopenharmony_ci
454275793eaSopenharmony_ci    /* compute bytes to read -- error on overflow */
455275793eaSopenharmony_ci    len = nitems * size;
456275793eaSopenharmony_ci    if (size && len / size != nitems) {
457275793eaSopenharmony_ci        gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
458275793eaSopenharmony_ci        return 0;
459275793eaSopenharmony_ci    }
460275793eaSopenharmony_ci
461275793eaSopenharmony_ci    /* read len or fewer bytes to buf, return the number of full items read */
462275793eaSopenharmony_ci    return len ? gz_read(state, buf, len) / size : 0;
463275793eaSopenharmony_ci}
464275793eaSopenharmony_ci
465275793eaSopenharmony_ci/* -- see zlib.h -- */
466275793eaSopenharmony_ci#ifdef Z_PREFIX_SET
467275793eaSopenharmony_ci#  undef z_gzgetc
468275793eaSopenharmony_ci#else
469275793eaSopenharmony_ci#  undef gzgetc
470275793eaSopenharmony_ci#endif
471275793eaSopenharmony_ciint ZEXPORT gzgetc(gzFile file)
472275793eaSopenharmony_ci{
473275793eaSopenharmony_ci    unsigned char buf[1];
474275793eaSopenharmony_ci    gz_statep state;
475275793eaSopenharmony_ci
476275793eaSopenharmony_ci    /* get internal structure */
477275793eaSopenharmony_ci    if (file == NULL)
478275793eaSopenharmony_ci    {
479275793eaSopenharmony_ci        return -1;
480275793eaSopenharmony_ci    }
481275793eaSopenharmony_ci    state = (gz_statep)file;
482275793eaSopenharmony_ci
483275793eaSopenharmony_ci    /* check that we're reading and that there's no (serious) error */
484275793eaSopenharmony_ci    if (state->mode != GZ_READ ||
485275793eaSopenharmony_ci        (state->err != Z_OK && state->err != Z_BUF_ERROR))
486275793eaSopenharmony_ci    {
487275793eaSopenharmony_ci        return -1;
488275793eaSopenharmony_ci    }
489275793eaSopenharmony_ci
490275793eaSopenharmony_ci    /* try output buffer (no need to check for skip request) */
491275793eaSopenharmony_ci    if (state->x.have) {
492275793eaSopenharmony_ci        state->x.have--;
493275793eaSopenharmony_ci        state->x.pos++;
494275793eaSopenharmony_ci        return *(state->x.next)++;
495275793eaSopenharmony_ci    }
496275793eaSopenharmony_ci
497275793eaSopenharmony_ci    /* nothing there -- try gz_read() */
498275793eaSopenharmony_ci    return gz_read(state, buf, 1) < 1 ? -1 : buf[0];
499275793eaSopenharmony_ci}
500275793eaSopenharmony_ci
501275793eaSopenharmony_ciint ZEXPORT gzgetc_(gzFile file)
502275793eaSopenharmony_ci{
503275793eaSopenharmony_ci    return gzgetc(file);
504275793eaSopenharmony_ci}
505275793eaSopenharmony_ci
506275793eaSopenharmony_ci/* -- see zlib.h -- */
507275793eaSopenharmony_ciint ZEXPORT gzungetc(int c, gzFile file)
508275793eaSopenharmony_ci{
509275793eaSopenharmony_ci    gz_statep state;
510275793eaSopenharmony_ci
511275793eaSopenharmony_ci    /* get internal structure */
512275793eaSopenharmony_ci    if (file == NULL)
513275793eaSopenharmony_ci    {
514275793eaSopenharmony_ci        return -1;
515275793eaSopenharmony_ci    }
516275793eaSopenharmony_ci    state = (gz_statep)file;
517275793eaSopenharmony_ci
518275793eaSopenharmony_ci    /* in case this was just opened, set up the input buffer */
519275793eaSopenharmony_ci    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
520275793eaSopenharmony_ci    {
521275793eaSopenharmony_ci        (void)gz_look(state);
522275793eaSopenharmony_ci    }
523275793eaSopenharmony_ci
524275793eaSopenharmony_ci    /* check that we're reading and that there's no (serious) error */
525275793eaSopenharmony_ci    if (state->mode != GZ_READ ||
526275793eaSopenharmony_ci        (state->err != Z_OK && state->err != Z_BUF_ERROR))
527275793eaSopenharmony_ci    {
528275793eaSopenharmony_ci        return -1;
529275793eaSopenharmony_ci    }
530275793eaSopenharmony_ci
531275793eaSopenharmony_ci    /* process a skip request */
532275793eaSopenharmony_ci    if (state->seek) {
533275793eaSopenharmony_ci        state->seek = 0;
534275793eaSopenharmony_ci        if (gz_skip(state, state->skip) == -1)
535275793eaSopenharmony_ci        {
536275793eaSopenharmony_ci            return -1;
537275793eaSopenharmony_ci        }
538275793eaSopenharmony_ci    }
539275793eaSopenharmony_ci
540275793eaSopenharmony_ci    /* can't push EOF */
541275793eaSopenharmony_ci    if (c < 0)
542275793eaSopenharmony_ci    {
543275793eaSopenharmony_ci        return -1;
544275793eaSopenharmony_ci    }
545275793eaSopenharmony_ci
546275793eaSopenharmony_ci    /* if output buffer empty, put byte at end (allows more pushing) */
547275793eaSopenharmony_ci    if (state->x.have == 0) {
548275793eaSopenharmony_ci        state->x.have = 1;
549275793eaSopenharmony_ci        state->x.next = state->out + (state->size << 1) - 1;
550275793eaSopenharmony_ci        state->x.next[0] = (unsigned char)c;
551275793eaSopenharmony_ci        state->x.pos--;
552275793eaSopenharmony_ci        state->past = 0;
553275793eaSopenharmony_ci        return c;
554275793eaSopenharmony_ci    }
555275793eaSopenharmony_ci
556275793eaSopenharmony_ci    /* if no room, give up (must have already done a gzungetc()) */
557275793eaSopenharmony_ci    if (state->x.have == (state->size << 1)) {
558275793eaSopenharmony_ci        gz_error(state, Z_DATA_ERROR, "out of room to push characters");
559275793eaSopenharmony_ci        return -1;
560275793eaSopenharmony_ci    }
561275793eaSopenharmony_ci
562275793eaSopenharmony_ci    /* slide output data if needed and insert byte before existing data */
563275793eaSopenharmony_ci    if (state->x.next == state->out) {
564275793eaSopenharmony_ci        unsigned char *src = state->out + state->x.have;
565275793eaSopenharmony_ci        unsigned char *dest = state->out + (state->size << 1);
566275793eaSopenharmony_ci        while (src > state->out){
567275793eaSopenharmony_ci            *--dest = *--src;
568275793eaSopenharmony_ci        }
569275793eaSopenharmony_ci        state->x.next = dest;
570275793eaSopenharmony_ci    }
571275793eaSopenharmony_ci    state->x.have++;
572275793eaSopenharmony_ci    state->x.next--;
573275793eaSopenharmony_ci    state->x.next[0] = (unsigned char)c;
574275793eaSopenharmony_ci    state->x.pos--;
575275793eaSopenharmony_ci    state->past = 0;
576275793eaSopenharmony_ci    return c;
577275793eaSopenharmony_ci}
578275793eaSopenharmony_ci
579275793eaSopenharmony_ci/* -- see zlib.h -- */
580275793eaSopenharmony_cichar * ZEXPORT gzgets(gzFile file, char *buf, int len)
581275793eaSopenharmony_ci{
582275793eaSopenharmony_ci    unsigned left, n;
583275793eaSopenharmony_ci    char *str;
584275793eaSopenharmony_ci    unsigned char *eol;
585275793eaSopenharmony_ci    gz_statep state;
586275793eaSopenharmony_ci
587275793eaSopenharmony_ci    /* check parameters and get internal structure */
588275793eaSopenharmony_ci    if (file == NULL || buf == NULL || len < 1)
589275793eaSopenharmony_ci    {
590275793eaSopenharmony_ci        return NULL;
591275793eaSopenharmony_ci    }
592275793eaSopenharmony_ci    state = (gz_statep)file;
593275793eaSopenharmony_ci
594275793eaSopenharmony_ci    /* check that we're reading and that there's no (serious) error */
595275793eaSopenharmony_ci    if (state->mode != GZ_READ ||
596275793eaSopenharmony_ci        (state->err != Z_OK && state->err != Z_BUF_ERROR))
597275793eaSopenharmony_ci    {
598275793eaSopenharmony_ci        return NULL;
599275793eaSopenharmony_ci    }
600275793eaSopenharmony_ci
601275793eaSopenharmony_ci    /* process a skip request */
602275793eaSopenharmony_ci    if (state->seek) {
603275793eaSopenharmony_ci        state->seek = 0;
604275793eaSopenharmony_ci        if (gz_skip(state, state->skip) == -1)
605275793eaSopenharmony_ci        {
606275793eaSopenharmony_ci            return NULL;
607275793eaSopenharmony_ci        }
608275793eaSopenharmony_ci    }
609275793eaSopenharmony_ci
610275793eaSopenharmony_ci    /* copy output bytes up to new line or len - 1, whichever comes first --
611275793eaSopenharmony_ci       append a terminating zero to the string (we don't check for a zero in
612275793eaSopenharmony_ci       the contents, let the user worry about that) */
613275793eaSopenharmony_ci    str = buf;
614275793eaSopenharmony_ci    left = (unsigned)len - 1;
615275793eaSopenharmony_ci    if (left) do {
616275793eaSopenharmony_ci        /* assure that something is in the output buffer */
617275793eaSopenharmony_ci        if (state->x.have == 0 && gz_fetch(state) == -1)
618275793eaSopenharmony_ci        {
619275793eaSopenharmony_ci            return NULL;                /* error */
620275793eaSopenharmony_ci        }
621275793eaSopenharmony_ci        if (state->x.have == 0) {       /* end of file */
622275793eaSopenharmony_ci            state->past = 1;            /* read past end */
623275793eaSopenharmony_ci            break;                      /* return what we have */
624275793eaSopenharmony_ci        }
625275793eaSopenharmony_ci
626275793eaSopenharmony_ci        /* look for end-of-line in current output buffer */
627275793eaSopenharmony_ci        n = state->x.have > left ? left : state->x.have;
628275793eaSopenharmony_ci        eol = (unsigned char *)memchr(state->x.next, '\n', n);
629275793eaSopenharmony_ci        if (eol != NULL)
630275793eaSopenharmony_ci        {
631275793eaSopenharmony_ci            n = (unsigned)(eol - state->x.next) + 1;
632275793eaSopenharmony_ci        }
633275793eaSopenharmony_ci
634275793eaSopenharmony_ci        /* copy through end-of-line, or remainder if not found */
635275793eaSopenharmony_ci        memcpy(buf, state->x.next, n);
636275793eaSopenharmony_ci        state->x.have -= n;
637275793eaSopenharmony_ci        state->x.next += n;
638275793eaSopenharmony_ci        state->x.pos += n;
639275793eaSopenharmony_ci        left -= n;
640275793eaSopenharmony_ci        buf += n;
641275793eaSopenharmony_ci    } while (left && eol == NULL);
642275793eaSopenharmony_ci
643275793eaSopenharmony_ci    /* return terminated string, or if nothing, end of file */
644275793eaSopenharmony_ci    if (buf == str)
645275793eaSopenharmony_ci    {
646275793eaSopenharmony_ci        return NULL;
647275793eaSopenharmony_ci    }
648275793eaSopenharmony_ci    buf[0] = 0;
649275793eaSopenharmony_ci    return str;
650275793eaSopenharmony_ci}
651275793eaSopenharmony_ci
652275793eaSopenharmony_ci/* -- see zlib.h -- */
653275793eaSopenharmony_ciint ZEXPORT gzdirect(gzFile file)
654275793eaSopenharmony_ci{
655275793eaSopenharmony_ci    gz_statep state;
656275793eaSopenharmony_ci
657275793eaSopenharmony_ci    /* get internal structure */
658275793eaSopenharmony_ci    if (file == NULL)
659275793eaSopenharmony_ci    {
660275793eaSopenharmony_ci        return 0;
661275793eaSopenharmony_ci    }
662275793eaSopenharmony_ci    state = (gz_statep)file;
663275793eaSopenharmony_ci
664275793eaSopenharmony_ci    /* if the state is not known, but we can find out, then do so (this is
665275793eaSopenharmony_ci       mainly for right after a gzopen() or gzdopen()) */
666275793eaSopenharmony_ci    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
667275793eaSopenharmony_ci    {
668275793eaSopenharmony_ci        (void)gz_look(state);
669275793eaSopenharmony_ci    }
670275793eaSopenharmony_ci
671275793eaSopenharmony_ci    /* return 1 if transparent, 0 if processing a gzip stream */
672275793eaSopenharmony_ci    return state->direct;
673275793eaSopenharmony_ci}
674275793eaSopenharmony_ci
675275793eaSopenharmony_ci/* -- see zlib.h -- */
676275793eaSopenharmony_ciint ZEXPORT gzclose_r(gzFile file)
677275793eaSopenharmony_ci{
678275793eaSopenharmony_ci    int ret, err;
679275793eaSopenharmony_ci    gz_statep state;
680275793eaSopenharmony_ci
681275793eaSopenharmony_ci    /* get internal structure */
682275793eaSopenharmony_ci    if (file == NULL)
683275793eaSopenharmony_ci    {
684275793eaSopenharmony_ci        return Z_STREAM_ERROR;
685275793eaSopenharmony_ci    }
686275793eaSopenharmony_ci    state = (gz_statep)file;
687275793eaSopenharmony_ci
688275793eaSopenharmony_ci    /* check that we're reading */
689275793eaSopenharmony_ci    if (state->mode != GZ_READ)
690275793eaSopenharmony_ci    {
691275793eaSopenharmony_ci        return Z_STREAM_ERROR;
692275793eaSopenharmony_ci    }
693275793eaSopenharmony_ci
694275793eaSopenharmony_ci    /* free memory and close file */
695275793eaSopenharmony_ci    if (state->size) {
696275793eaSopenharmony_ci        inflateEnd(&(state->strm));
697275793eaSopenharmony_ci        free(state->out);
698275793eaSopenharmony_ci        free(state->in);
699275793eaSopenharmony_ci    }
700275793eaSopenharmony_ci    err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
701275793eaSopenharmony_ci    gz_error(state, Z_OK, NULL);
702275793eaSopenharmony_ci    free(state->path);
703275793eaSopenharmony_ci    ret = close(state->fd);
704275793eaSopenharmony_ci    free(state);
705275793eaSopenharmony_ci    return ret ? Z_ERRNO : err;
706275793eaSopenharmony_ci}
707