xref: /aosp_15_r20/external/elfutils/libdwfl/gzip.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Decompression support for libdwfl: zlib (gzip) and/or bzlib (bzip2).
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2009 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker 
5*7304104dSAndroid Build Coastguard Worker    This file is free software; you can redistribute it and/or modify
6*7304104dSAndroid Build Coastguard Worker    it under the terms of either
7*7304104dSAndroid Build Coastguard Worker 
8*7304104dSAndroid Build Coastguard Worker      * the GNU Lesser General Public License as published by the Free
9*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 3 of the License, or (at
10*7304104dSAndroid Build Coastguard Worker        your option) any later version
11*7304104dSAndroid Build Coastguard Worker 
12*7304104dSAndroid Build Coastguard Worker    or
13*7304104dSAndroid Build Coastguard Worker 
14*7304104dSAndroid Build Coastguard Worker      * the GNU General Public License as published by the Free
15*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 2 of the License, or (at
16*7304104dSAndroid Build Coastguard Worker        your option) any later version
17*7304104dSAndroid Build Coastguard Worker 
18*7304104dSAndroid Build Coastguard Worker    or both in parallel, as here.
19*7304104dSAndroid Build Coastguard Worker 
20*7304104dSAndroid Build Coastguard Worker    elfutils is distributed in the hope that it will be useful, but
21*7304104dSAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
22*7304104dSAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23*7304104dSAndroid Build Coastguard Worker    General Public License for more details.
24*7304104dSAndroid Build Coastguard Worker 
25*7304104dSAndroid Build Coastguard Worker    You should have received copies of the GNU General Public License and
26*7304104dSAndroid Build Coastguard Worker    the GNU Lesser General Public License along with this program.  If
27*7304104dSAndroid Build Coastguard Worker    not, see <http://www.gnu.org/licenses/>.  */
28*7304104dSAndroid Build Coastguard Worker 
29*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
30*7304104dSAndroid Build Coastguard Worker # include <config.h>
31*7304104dSAndroid Build Coastguard Worker #endif
32*7304104dSAndroid Build Coastguard Worker 
33*7304104dSAndroid Build Coastguard Worker #include "libdwflP.h"
34*7304104dSAndroid Build Coastguard Worker #include "system.h"
35*7304104dSAndroid Build Coastguard Worker 
36*7304104dSAndroid Build Coastguard Worker #ifdef LZMA
37*7304104dSAndroid Build Coastguard Worker # define USE_INFLATE	1
38*7304104dSAndroid Build Coastguard Worker # include <lzma.h>
39*7304104dSAndroid Build Coastguard Worker # define unzip		__libdw_unlzma
40*7304104dSAndroid Build Coastguard Worker # define DWFL_E_ZLIB	DWFL_E_LZMA
41*7304104dSAndroid Build Coastguard Worker # define MAGIC		"\xFD" "7zXZ\0" /* XZ file format.  */
42*7304104dSAndroid Build Coastguard Worker # define MAGIC2		"\x5d\0"	/* Raw LZMA format.  */
43*7304104dSAndroid Build Coastguard Worker # define Z(what)	LZMA_##what
44*7304104dSAndroid Build Coastguard Worker # define LZMA_ERRNO	LZMA_PROG_ERROR
45*7304104dSAndroid Build Coastguard Worker # define z_stream	lzma_stream
46*7304104dSAndroid Build Coastguard Worker # define inflateInit(z)	lzma_auto_decoder (z, 1 << 30, 0)
47*7304104dSAndroid Build Coastguard Worker # define do_inflate(z)	lzma_code (z, LZMA_RUN)
48*7304104dSAndroid Build Coastguard Worker # define inflateEnd(z)	lzma_end (z)
49*7304104dSAndroid Build Coastguard Worker #elif defined ZSTD
50*7304104dSAndroid Build Coastguard Worker # define USE_INFLATE	1
51*7304104dSAndroid Build Coastguard Worker # include <zstd.h>
52*7304104dSAndroid Build Coastguard Worker # define unzip		__libdw_unzstd
53*7304104dSAndroid Build Coastguard Worker # define DWFL_E_ZLIB	DWFL_E_ZSTD
54*7304104dSAndroid Build Coastguard Worker # define MAGIC		"\x28\xb5\x2f\xfd"
55*7304104dSAndroid Build Coastguard Worker #elif defined BZLIB
56*7304104dSAndroid Build Coastguard Worker # define USE_INFLATE	1
57*7304104dSAndroid Build Coastguard Worker # include <bzlib.h>
58*7304104dSAndroid Build Coastguard Worker # define unzip		__libdw_bunzip2
59*7304104dSAndroid Build Coastguard Worker # define DWFL_E_ZLIB	DWFL_E_BZLIB
60*7304104dSAndroid Build Coastguard Worker # define MAGIC		"BZh"
61*7304104dSAndroid Build Coastguard Worker # define Z(what)	BZ_##what
62*7304104dSAndroid Build Coastguard Worker # define BZ_ERRNO	BZ_IO_ERROR
63*7304104dSAndroid Build Coastguard Worker # define z_stream	bz_stream
64*7304104dSAndroid Build Coastguard Worker # define inflateInit(z)	BZ2_bzDecompressInit (z, 0, 0)
65*7304104dSAndroid Build Coastguard Worker # define do_inflate(z)	BZ2_bzDecompress (z)
66*7304104dSAndroid Build Coastguard Worker # define inflateEnd(z)	BZ2_bzDecompressEnd (z)
67*7304104dSAndroid Build Coastguard Worker #else
68*7304104dSAndroid Build Coastguard Worker # define USE_INFLATE	0
69*7304104dSAndroid Build Coastguard Worker # define crc32		loser_crc32
70*7304104dSAndroid Build Coastguard Worker # include <zlib.h>
71*7304104dSAndroid Build Coastguard Worker # define unzip		__libdw_gunzip
72*7304104dSAndroid Build Coastguard Worker # define MAGIC		"\037\213"
73*7304104dSAndroid Build Coastguard Worker # define Z(what)	Z_##what
74*7304104dSAndroid Build Coastguard Worker #endif
75*7304104dSAndroid Build Coastguard Worker 
76*7304104dSAndroid Build Coastguard Worker #define READ_SIZE		(1 << 20)
77*7304104dSAndroid Build Coastguard Worker 
78*7304104dSAndroid Build Coastguard Worker struct unzip_state {
79*7304104dSAndroid Build Coastguard Worker #if !USE_INFLATE
80*7304104dSAndroid Build Coastguard Worker   gzFile zf;
81*7304104dSAndroid Build Coastguard Worker #endif
82*7304104dSAndroid Build Coastguard Worker   size_t mapped_size;
83*7304104dSAndroid Build Coastguard Worker   void **whole;
84*7304104dSAndroid Build Coastguard Worker   void *buffer;
85*7304104dSAndroid Build Coastguard Worker   size_t size;
86*7304104dSAndroid Build Coastguard Worker   void *input_buffer;
87*7304104dSAndroid Build Coastguard Worker   off_t input_pos;
88*7304104dSAndroid Build Coastguard Worker };
89*7304104dSAndroid Build Coastguard Worker 
90*7304104dSAndroid Build Coastguard Worker static inline bool
bigger_buffer(struct unzip_state * state,size_t start)91*7304104dSAndroid Build Coastguard Worker bigger_buffer (struct unzip_state *state, size_t start)
92*7304104dSAndroid Build Coastguard Worker {
93*7304104dSAndroid Build Coastguard Worker   size_t more = state->size ? state->size * 2 : start;
94*7304104dSAndroid Build Coastguard Worker   char *b = realloc (state->buffer, more);
95*7304104dSAndroid Build Coastguard Worker   while (unlikely (b == NULL) && more >= state->size + 1024)
96*7304104dSAndroid Build Coastguard Worker     b = realloc (state->buffer, more -= 1024);
97*7304104dSAndroid Build Coastguard Worker   if (unlikely (b == NULL))
98*7304104dSAndroid Build Coastguard Worker     return false;
99*7304104dSAndroid Build Coastguard Worker   state->buffer = b;
100*7304104dSAndroid Build Coastguard Worker   state->size = more;
101*7304104dSAndroid Build Coastguard Worker   return true;
102*7304104dSAndroid Build Coastguard Worker }
103*7304104dSAndroid Build Coastguard Worker 
104*7304104dSAndroid Build Coastguard Worker static inline void
smaller_buffer(struct unzip_state * state,size_t end)105*7304104dSAndroid Build Coastguard Worker smaller_buffer (struct unzip_state *state, size_t end)
106*7304104dSAndroid Build Coastguard Worker {
107*7304104dSAndroid Build Coastguard Worker   state->buffer =
108*7304104dSAndroid Build Coastguard Worker       realloc (state->buffer, end) ?: end == 0 ? NULL : state->buffer;
109*7304104dSAndroid Build Coastguard Worker   state->size = end;
110*7304104dSAndroid Build Coastguard Worker }
111*7304104dSAndroid Build Coastguard Worker 
112*7304104dSAndroid Build Coastguard Worker static inline Dwfl_Error
fail(struct unzip_state * state,Dwfl_Error failure)113*7304104dSAndroid Build Coastguard Worker fail (struct unzip_state *state, Dwfl_Error failure)
114*7304104dSAndroid Build Coastguard Worker {
115*7304104dSAndroid Build Coastguard Worker   if (state->input_pos == (off_t) state->mapped_size)
116*7304104dSAndroid Build Coastguard Worker     *state->whole = state->input_buffer;
117*7304104dSAndroid Build Coastguard Worker   else
118*7304104dSAndroid Build Coastguard Worker     {
119*7304104dSAndroid Build Coastguard Worker       free (state->input_buffer);
120*7304104dSAndroid Build Coastguard Worker       *state->whole = NULL;
121*7304104dSAndroid Build Coastguard Worker     }
122*7304104dSAndroid Build Coastguard Worker   free (state->buffer);
123*7304104dSAndroid Build Coastguard Worker   return failure;
124*7304104dSAndroid Build Coastguard Worker }
125*7304104dSAndroid Build Coastguard Worker 
126*7304104dSAndroid Build Coastguard Worker #ifndef ZSTD
127*7304104dSAndroid Build Coastguard Worker static inline Dwfl_Error
zlib_fail(struct unzip_state * state,int result)128*7304104dSAndroid Build Coastguard Worker zlib_fail (struct unzip_state *state, int result)
129*7304104dSAndroid Build Coastguard Worker {
130*7304104dSAndroid Build Coastguard Worker   switch (result)
131*7304104dSAndroid Build Coastguard Worker     {
132*7304104dSAndroid Build Coastguard Worker     case Z (MEM_ERROR):
133*7304104dSAndroid Build Coastguard Worker       return fail (state, DWFL_E_NOMEM);
134*7304104dSAndroid Build Coastguard Worker     case Z (ERRNO):
135*7304104dSAndroid Build Coastguard Worker       return fail (state, DWFL_E_ERRNO);
136*7304104dSAndroid Build Coastguard Worker     default:
137*7304104dSAndroid Build Coastguard Worker       return fail (state, DWFL_E_ZLIB);
138*7304104dSAndroid Build Coastguard Worker     }
139*7304104dSAndroid Build Coastguard Worker }
140*7304104dSAndroid Build Coastguard Worker #endif
141*7304104dSAndroid Build Coastguard Worker 
142*7304104dSAndroid Build Coastguard Worker #if !USE_INFLATE
143*7304104dSAndroid Build Coastguard Worker static Dwfl_Error
open_stream(int fd,off_t start_offset,struct unzip_state * state)144*7304104dSAndroid Build Coastguard Worker open_stream (int fd, off_t start_offset, struct unzip_state *state)
145*7304104dSAndroid Build Coastguard Worker {
146*7304104dSAndroid Build Coastguard Worker     int d = dup (fd);
147*7304104dSAndroid Build Coastguard Worker     if (unlikely (d < 0))
148*7304104dSAndroid Build Coastguard Worker       return DWFL_E_ERRNO;
149*7304104dSAndroid Build Coastguard Worker     if (start_offset != 0)
150*7304104dSAndroid Build Coastguard Worker       {
151*7304104dSAndroid Build Coastguard Worker 	off_t off = lseek (d, start_offset, SEEK_SET);
152*7304104dSAndroid Build Coastguard Worker 	if (off != start_offset)
153*7304104dSAndroid Build Coastguard Worker 	  {
154*7304104dSAndroid Build Coastguard Worker 	    close (d);
155*7304104dSAndroid Build Coastguard Worker 	    return DWFL_E_ERRNO;
156*7304104dSAndroid Build Coastguard Worker 	  }
157*7304104dSAndroid Build Coastguard Worker       }
158*7304104dSAndroid Build Coastguard Worker     state->zf = gzdopen (d, "r");
159*7304104dSAndroid Build Coastguard Worker     if (unlikely (state->zf == NULL))
160*7304104dSAndroid Build Coastguard Worker       {
161*7304104dSAndroid Build Coastguard Worker 	close (d);
162*7304104dSAndroid Build Coastguard Worker 	return DWFL_E_NOMEM;
163*7304104dSAndroid Build Coastguard Worker       }
164*7304104dSAndroid Build Coastguard Worker 
165*7304104dSAndroid Build Coastguard Worker     /* From here on, zlib will close D.  */
166*7304104dSAndroid Build Coastguard Worker 
167*7304104dSAndroid Build Coastguard Worker     return DWFL_E_NOERROR;
168*7304104dSAndroid Build Coastguard Worker }
169*7304104dSAndroid Build Coastguard Worker #endif
170*7304104dSAndroid Build Coastguard Worker 
171*7304104dSAndroid Build Coastguard Worker /* If this is not a compressed image, return DWFL_E_BADELF.
172*7304104dSAndroid Build Coastguard Worker    If we uncompressed it into *WHOLE, *WHOLE_SIZE, return DWFL_E_NOERROR.
173*7304104dSAndroid Build Coastguard Worker    Otherwise return an error for bad compressed data or I/O failure.
174*7304104dSAndroid Build Coastguard Worker    If we return an error after reading the first part of the file,
175*7304104dSAndroid Build Coastguard Worker    leave that portion malloc'd in *WHOLE, *WHOLE_SIZE.  If *WHOLE
176*7304104dSAndroid Build Coastguard Worker    is not null on entry, we'll use it in lieu of repeating a read.  */
177*7304104dSAndroid Build Coastguard Worker 
178*7304104dSAndroid Build Coastguard Worker Dwfl_Error internal_function
unzip(int fd,off_t start_offset,void * mapped,size_t _mapped_size,void ** _whole,size_t * whole_size)179*7304104dSAndroid Build Coastguard Worker unzip (int fd, off_t start_offset,
180*7304104dSAndroid Build Coastguard Worker        void *mapped, size_t _mapped_size,
181*7304104dSAndroid Build Coastguard Worker        void **_whole, size_t *whole_size)
182*7304104dSAndroid Build Coastguard Worker {
183*7304104dSAndroid Build Coastguard Worker   struct unzip_state state =
184*7304104dSAndroid Build Coastguard Worker     {
185*7304104dSAndroid Build Coastguard Worker #if !USE_INFLATE
186*7304104dSAndroid Build Coastguard Worker       .zf = NULL,
187*7304104dSAndroid Build Coastguard Worker #endif
188*7304104dSAndroid Build Coastguard Worker       .mapped_size = _mapped_size,
189*7304104dSAndroid Build Coastguard Worker       .whole = _whole,
190*7304104dSAndroid Build Coastguard Worker       .buffer = NULL,
191*7304104dSAndroid Build Coastguard Worker       .size = 0,
192*7304104dSAndroid Build Coastguard Worker       .input_buffer = NULL,
193*7304104dSAndroid Build Coastguard Worker       .input_pos = 0
194*7304104dSAndroid Build Coastguard Worker     };
195*7304104dSAndroid Build Coastguard Worker 
196*7304104dSAndroid Build Coastguard Worker   if (mapped == NULL)
197*7304104dSAndroid Build Coastguard Worker     {
198*7304104dSAndroid Build Coastguard Worker       if (*state.whole == NULL)
199*7304104dSAndroid Build Coastguard Worker 	{
200*7304104dSAndroid Build Coastguard Worker 	  state.input_buffer = malloc (READ_SIZE);
201*7304104dSAndroid Build Coastguard Worker 	  if (unlikely (state.input_buffer == NULL))
202*7304104dSAndroid Build Coastguard Worker 	    return DWFL_E_NOMEM;
203*7304104dSAndroid Build Coastguard Worker 
204*7304104dSAndroid Build Coastguard Worker 	  ssize_t n = pread_retry (fd, state.input_buffer, READ_SIZE, start_offset);
205*7304104dSAndroid Build Coastguard Worker 	  if (unlikely (n < 0))
206*7304104dSAndroid Build Coastguard Worker 	    return fail (&state, DWFL_E_ERRNO);
207*7304104dSAndroid Build Coastguard Worker 
208*7304104dSAndroid Build Coastguard Worker 	  state.input_pos = n;
209*7304104dSAndroid Build Coastguard Worker 	  mapped = state.input_buffer;
210*7304104dSAndroid Build Coastguard Worker 	  state.mapped_size = n;
211*7304104dSAndroid Build Coastguard Worker 	}
212*7304104dSAndroid Build Coastguard Worker       else
213*7304104dSAndroid Build Coastguard Worker 	{
214*7304104dSAndroid Build Coastguard Worker 	  state.input_buffer = *state.whole;
215*7304104dSAndroid Build Coastguard Worker 	  state.input_pos = state.mapped_size = *whole_size;
216*7304104dSAndroid Build Coastguard Worker 	}
217*7304104dSAndroid Build Coastguard Worker     }
218*7304104dSAndroid Build Coastguard Worker 
219*7304104dSAndroid Build Coastguard Worker #define NOMAGIC(magic) \
220*7304104dSAndroid Build Coastguard Worker   (state.mapped_size <= sizeof magic || \
221*7304104dSAndroid Build Coastguard Worker    memcmp (mapped, magic, sizeof magic - 1))
222*7304104dSAndroid Build Coastguard Worker 
223*7304104dSAndroid Build Coastguard Worker   /* First, look at the header.  */
224*7304104dSAndroid Build Coastguard Worker   if (NOMAGIC (MAGIC)
225*7304104dSAndroid Build Coastguard Worker #ifdef MAGIC2
226*7304104dSAndroid Build Coastguard Worker       && NOMAGIC (MAGIC2)
227*7304104dSAndroid Build Coastguard Worker #endif
228*7304104dSAndroid Build Coastguard Worker       )
229*7304104dSAndroid Build Coastguard Worker     /* Not a compressed file.  */
230*7304104dSAndroid Build Coastguard Worker     return fail (&state, DWFL_E_BADELF);
231*7304104dSAndroid Build Coastguard Worker 
232*7304104dSAndroid Build Coastguard Worker #ifdef ZSTD
233*7304104dSAndroid Build Coastguard Worker   /* special case for libzstd since it is slightly different from the
234*7304104dSAndroid Build Coastguard Worker      API provided by bzlib and liblzma.  */
235*7304104dSAndroid Build Coastguard Worker 
236*7304104dSAndroid Build Coastguard Worker   void *next_in = mapped;
237*7304104dSAndroid Build Coastguard Worker   size_t avail_in = state.mapped_size;
238*7304104dSAndroid Build Coastguard Worker   void *next_out = NULL;
239*7304104dSAndroid Build Coastguard Worker   size_t avail_out = 0;
240*7304104dSAndroid Build Coastguard Worker   size_t total_out = 0;
241*7304104dSAndroid Build Coastguard Worker 
242*7304104dSAndroid Build Coastguard Worker   size_t result;
243*7304104dSAndroid Build Coastguard Worker   ZSTD_DCtx *dctx = ZSTD_createDCtx();
244*7304104dSAndroid Build Coastguard Worker   if (dctx == NULL)
245*7304104dSAndroid Build Coastguard Worker     return fail (&state, DWFL_E_NOMEM);
246*7304104dSAndroid Build Coastguard Worker 
247*7304104dSAndroid Build Coastguard Worker   do
248*7304104dSAndroid Build Coastguard Worker     {
249*7304104dSAndroid Build Coastguard Worker       if (avail_in == 0 && state.input_buffer != NULL)
250*7304104dSAndroid Build Coastguard Worker 	{
251*7304104dSAndroid Build Coastguard Worker 	  ssize_t n = pread_retry (fd, state.input_buffer, READ_SIZE,
252*7304104dSAndroid Build Coastguard Worker 				   start_offset + state.input_pos);
253*7304104dSAndroid Build Coastguard Worker 	  if (unlikely (n < 0))
254*7304104dSAndroid Build Coastguard Worker 	    {
255*7304104dSAndroid Build Coastguard Worker 	      ZSTD_freeDCtx (dctx);
256*7304104dSAndroid Build Coastguard Worker 	      return fail (&state, DWFL_E_ERRNO);
257*7304104dSAndroid Build Coastguard Worker 	    }
258*7304104dSAndroid Build Coastguard Worker 	  next_in = state.input_buffer;
259*7304104dSAndroid Build Coastguard Worker 	  avail_in = n;
260*7304104dSAndroid Build Coastguard Worker 	  state.input_pos += n;
261*7304104dSAndroid Build Coastguard Worker 	}
262*7304104dSAndroid Build Coastguard Worker       if (avail_out == 0)
263*7304104dSAndroid Build Coastguard Worker 	{
264*7304104dSAndroid Build Coastguard Worker 	  ptrdiff_t pos = (void *) next_out - state.buffer;
265*7304104dSAndroid Build Coastguard Worker 	  if (!bigger_buffer (&state, avail_in))
266*7304104dSAndroid Build Coastguard Worker 	    {
267*7304104dSAndroid Build Coastguard Worker 	      ZSTD_freeDCtx (dctx);
268*7304104dSAndroid Build Coastguard Worker 	      return fail (&state, DWFL_E_NOMEM);
269*7304104dSAndroid Build Coastguard Worker 	    }
270*7304104dSAndroid Build Coastguard Worker 	  next_out = state.buffer + pos;
271*7304104dSAndroid Build Coastguard Worker 	  avail_out = state.size - pos;
272*7304104dSAndroid Build Coastguard Worker 	}
273*7304104dSAndroid Build Coastguard Worker 
274*7304104dSAndroid Build Coastguard Worker       ZSTD_inBuffer input = { next_in, avail_in, 0 };
275*7304104dSAndroid Build Coastguard Worker       ZSTD_outBuffer output = { next_out, avail_out, 0 };
276*7304104dSAndroid Build Coastguard Worker       result = ZSTD_decompressStream (dctx, &output, &input);
277*7304104dSAndroid Build Coastguard Worker 
278*7304104dSAndroid Build Coastguard Worker       if (! ZSTD_isError (result))
279*7304104dSAndroid Build Coastguard Worker 	{
280*7304104dSAndroid Build Coastguard Worker 	  total_out += output.pos;
281*7304104dSAndroid Build Coastguard Worker 	  next_out += output.pos;
282*7304104dSAndroid Build Coastguard Worker 	  avail_out -= output.pos;
283*7304104dSAndroid Build Coastguard Worker 	  next_in += input.pos;
284*7304104dSAndroid Build Coastguard Worker 	  avail_in -= input.pos;
285*7304104dSAndroid Build Coastguard Worker 	}
286*7304104dSAndroid Build Coastguard Worker 
287*7304104dSAndroid Build Coastguard Worker       if (result == 0)
288*7304104dSAndroid Build Coastguard Worker 	break;
289*7304104dSAndroid Build Coastguard Worker     }
290*7304104dSAndroid Build Coastguard Worker   while (avail_in > 0 && ! ZSTD_isError (result));
291*7304104dSAndroid Build Coastguard Worker 
292*7304104dSAndroid Build Coastguard Worker   ZSTD_freeDCtx (dctx);
293*7304104dSAndroid Build Coastguard Worker 
294*7304104dSAndroid Build Coastguard Worker   if (ZSTD_isError (result))
295*7304104dSAndroid Build Coastguard Worker     return fail (&state, DWFL_E_ZSTD);
296*7304104dSAndroid Build Coastguard Worker 
297*7304104dSAndroid Build Coastguard Worker   smaller_buffer (&state, total_out);
298*7304104dSAndroid Build Coastguard Worker 
299*7304104dSAndroid Build Coastguard Worker #elif USE_INFLATE
300*7304104dSAndroid Build Coastguard Worker 
301*7304104dSAndroid Build Coastguard Worker   /* This style actually only works with bzlib and liblzma.
302*7304104dSAndroid Build Coastguard Worker      The stupid zlib interface has nothing to grok the
303*7304104dSAndroid Build Coastguard Worker      gzip file headers except the slow gzFile interface.  */
304*7304104dSAndroid Build Coastguard Worker 
305*7304104dSAndroid Build Coastguard Worker   z_stream z = { .next_in = mapped, .avail_in = state.mapped_size };
306*7304104dSAndroid Build Coastguard Worker   int result = inflateInit (&z);
307*7304104dSAndroid Build Coastguard Worker   if (result != Z (OK))
308*7304104dSAndroid Build Coastguard Worker     {
309*7304104dSAndroid Build Coastguard Worker       inflateEnd (&z);
310*7304104dSAndroid Build Coastguard Worker       return zlib_fail (&state, result);
311*7304104dSAndroid Build Coastguard Worker     }
312*7304104dSAndroid Build Coastguard Worker 
313*7304104dSAndroid Build Coastguard Worker   do
314*7304104dSAndroid Build Coastguard Worker     {
315*7304104dSAndroid Build Coastguard Worker       if (z.avail_in == 0 && state.input_buffer != NULL)
316*7304104dSAndroid Build Coastguard Worker 	{
317*7304104dSAndroid Build Coastguard Worker 	  ssize_t n = pread_retry (fd, state.input_buffer, READ_SIZE,
318*7304104dSAndroid Build Coastguard Worker 				   start_offset + state.input_pos);
319*7304104dSAndroid Build Coastguard Worker 	  if (unlikely (n < 0))
320*7304104dSAndroid Build Coastguard Worker 	    {
321*7304104dSAndroid Build Coastguard Worker 	      inflateEnd (&z);
322*7304104dSAndroid Build Coastguard Worker 	      return zlib_fail (&state, Z (ERRNO));
323*7304104dSAndroid Build Coastguard Worker 	    }
324*7304104dSAndroid Build Coastguard Worker 	  z.next_in = state.input_buffer;
325*7304104dSAndroid Build Coastguard Worker 	  z.avail_in = n;
326*7304104dSAndroid Build Coastguard Worker 	  state.input_pos += n;
327*7304104dSAndroid Build Coastguard Worker 	}
328*7304104dSAndroid Build Coastguard Worker       if (z.avail_out == 0)
329*7304104dSAndroid Build Coastguard Worker 	{
330*7304104dSAndroid Build Coastguard Worker 	  ptrdiff_t pos = (void *) z.next_out - state.buffer;
331*7304104dSAndroid Build Coastguard Worker 	  if (!bigger_buffer (&state, z.avail_in))
332*7304104dSAndroid Build Coastguard Worker 	    {
333*7304104dSAndroid Build Coastguard Worker 	      result = Z (MEM_ERROR);
334*7304104dSAndroid Build Coastguard Worker 	      break;
335*7304104dSAndroid Build Coastguard Worker 	    }
336*7304104dSAndroid Build Coastguard Worker 	  z.next_out = state.buffer + pos;
337*7304104dSAndroid Build Coastguard Worker 	  z.avail_out = state.size - pos;
338*7304104dSAndroid Build Coastguard Worker 	}
339*7304104dSAndroid Build Coastguard Worker     }
340*7304104dSAndroid Build Coastguard Worker   while ((result = do_inflate (&z)) == Z (OK));
341*7304104dSAndroid Build Coastguard Worker 
342*7304104dSAndroid Build Coastguard Worker #ifdef BZLIB
343*7304104dSAndroid Build Coastguard Worker   uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32)
344*7304104dSAndroid Build Coastguard Worker 			| z.total_out_lo32);
345*7304104dSAndroid Build Coastguard Worker   smaller_buffer (&state, total_out);
346*7304104dSAndroid Build Coastguard Worker #else
347*7304104dSAndroid Build Coastguard Worker   smaller_buffer (&state, z.total_out);
348*7304104dSAndroid Build Coastguard Worker #endif
349*7304104dSAndroid Build Coastguard Worker 
350*7304104dSAndroid Build Coastguard Worker   inflateEnd (&z);
351*7304104dSAndroid Build Coastguard Worker 
352*7304104dSAndroid Build Coastguard Worker   if (result != Z (STREAM_END))
353*7304104dSAndroid Build Coastguard Worker     return zlib_fail (&state, result);
354*7304104dSAndroid Build Coastguard Worker 
355*7304104dSAndroid Build Coastguard Worker #else  /* gzip only.  */
356*7304104dSAndroid Build Coastguard Worker 
357*7304104dSAndroid Build Coastguard Worker   /* Let the decompression library read the file directly.  */
358*7304104dSAndroid Build Coastguard Worker 
359*7304104dSAndroid Build Coastguard Worker   Dwfl_Error result = open_stream (fd, start_offset, &state);
360*7304104dSAndroid Build Coastguard Worker 
361*7304104dSAndroid Build Coastguard Worker   if (result == DWFL_E_NOERROR && gzdirect (state.zf))
362*7304104dSAndroid Build Coastguard Worker     {
363*7304104dSAndroid Build Coastguard Worker       gzclose (state.zf);
364*7304104dSAndroid Build Coastguard Worker       /* Not a compressed stream after all.  */
365*7304104dSAndroid Build Coastguard Worker       return fail (&state, DWFL_E_BADELF);
366*7304104dSAndroid Build Coastguard Worker     }
367*7304104dSAndroid Build Coastguard Worker 
368*7304104dSAndroid Build Coastguard Worker   if (result != DWFL_E_NOERROR)
369*7304104dSAndroid Build Coastguard Worker     return fail (&state, result);
370*7304104dSAndroid Build Coastguard Worker 
371*7304104dSAndroid Build Coastguard Worker   ptrdiff_t pos = 0;
372*7304104dSAndroid Build Coastguard Worker   while (1)
373*7304104dSAndroid Build Coastguard Worker     {
374*7304104dSAndroid Build Coastguard Worker       if (!bigger_buffer (&state, 1024))
375*7304104dSAndroid Build Coastguard Worker 	{
376*7304104dSAndroid Build Coastguard Worker 	  gzclose (state.zf);
377*7304104dSAndroid Build Coastguard Worker 	  return zlib_fail (&state, Z (MEM_ERROR));
378*7304104dSAndroid Build Coastguard Worker 	}
379*7304104dSAndroid Build Coastguard Worker       int n = gzread (state.zf, state.buffer + pos, state.size - pos);
380*7304104dSAndroid Build Coastguard Worker       if (n < 0)
381*7304104dSAndroid Build Coastguard Worker 	{
382*7304104dSAndroid Build Coastguard Worker 	  int code;
383*7304104dSAndroid Build Coastguard Worker 	  gzerror (state.zf, &code);
384*7304104dSAndroid Build Coastguard Worker 	  gzclose (state.zf);
385*7304104dSAndroid Build Coastguard Worker 	  return zlib_fail (&state, code);
386*7304104dSAndroid Build Coastguard Worker 	}
387*7304104dSAndroid Build Coastguard Worker       if (n == 0)
388*7304104dSAndroid Build Coastguard Worker 	break;
389*7304104dSAndroid Build Coastguard Worker       pos += n;
390*7304104dSAndroid Build Coastguard Worker     }
391*7304104dSAndroid Build Coastguard Worker 
392*7304104dSAndroid Build Coastguard Worker   gzclose (state.zf);
393*7304104dSAndroid Build Coastguard Worker   smaller_buffer (&state, pos);
394*7304104dSAndroid Build Coastguard Worker #endif
395*7304104dSAndroid Build Coastguard Worker 
396*7304104dSAndroid Build Coastguard Worker   free (state.input_buffer);
397*7304104dSAndroid Build Coastguard Worker 
398*7304104dSAndroid Build Coastguard Worker   *state.whole = state.buffer;
399*7304104dSAndroid Build Coastguard Worker   *whole_size = state.size;
400*7304104dSAndroid Build Coastguard Worker 
401*7304104dSAndroid Build Coastguard Worker   return DWFL_E_NOERROR;
402*7304104dSAndroid Build Coastguard Worker }
403