Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | /*
* Copyright 2007 David Gibson, IBM Corporation.
* Based on earlier work, Copyright (C) Paul Mackerras 1997.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <stddef.h>
#include "string.h"
#include "stdio.h"
#include "ops.h"
#include "gunzip_util.h"
#define HEAD_CRC 2
#define EXTRA_FIELD 4
#define ORIG_NAME 8
#define COMMENT 0x10
#define RESERVED 0xe0
/**
* gunzip_start - prepare to decompress gzip data
* @state: decompressor state structure to be initialized
* @src: buffer containing gzip compressed or uncompressed data
* @srclen: size in bytes of the buffer at src
*
* If the buffer at @src contains a gzip header, this function
* initializes zlib to decompress the data, storing the decompression
* state in @state. The other functions in this file can then be used
* to decompress data from the gzipped stream.
*
* If the buffer at @src does not contain a gzip header, it is assumed
* to contain uncompressed data. The buffer information is recorded
* in @state and the other functions in this file will simply copy
* data from the uncompressed data stream at @src.
*
* Any errors, such as bad compressed data, cause an error to be
* printed an the platform's exit() function to be called.
*/
void gunzip_start(struct gunzip_state *state, void *src, int srclen)
{
char *hdr = src;
int hdrlen = 0;
memset(state, 0, sizeof(*state));
/* Check for gzip magic number */
if ((hdr[0] == 0x1f) && (hdr[1] == 0x8b)) {
/* gzip data, initialize zlib parameters */
int r, flags;
state->s.workspace = state->scratch;
if (zlib_inflate_workspacesize() > sizeof(state->scratch))
fatal("insufficient scratch space for gunzip\n\r");
/* skip header */
hdrlen = 10;
flags = hdr[3];
if (hdr[2] != Z_DEFLATED || (flags & RESERVED) != 0)
fatal("bad gzipped data\n\r");
if ((flags & EXTRA_FIELD) != 0)
hdrlen = 12 + hdr[10] + (hdr[11] << 8);
if ((flags & ORIG_NAME) != 0)
while (hdr[hdrlen++] != 0)
;
if ((flags & COMMENT) != 0)
while (hdr[hdrlen++] != 0)
;
if ((flags & HEAD_CRC) != 0)
hdrlen += 2;
if (hdrlen >= srclen)
fatal("gunzip_start: ran out of data in header\n\r");
r = zlib_inflateInit2(&state->s, -MAX_WBITS);
if (r != Z_OK)
fatal("inflateInit2 returned %d\n\r", r);
}
state->s.total_in = hdrlen;
state->s.next_in = src + hdrlen;
state->s.avail_in = srclen - hdrlen;
}
/**
* gunzip_partial - extract bytes from a gzip data stream
* @state: gzip state structure previously initialized by gunzip_start()
* @dst: buffer to store extracted data
* @dstlen: maximum number of bytes to extract
*
* This function extracts at most @dstlen bytes from the data stream
* previously associated with @state by gunzip_start(), decompressing
* if necessary. Exactly @dstlen bytes are extracted unless the data
* stream doesn't contain enough bytes, in which case the entire
* remainder of the stream is decompressed.
*
* Returns the actual number of bytes extracted. If any errors occur,
* such as a corrupted compressed stream, an error is printed an the
* platform's exit() function is called.
*/
int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen)
{
int len;
if (state->s.workspace) {
/* gunzipping */
int r;
state->s.next_out = dst;
state->s.avail_out = dstlen;
r = zlib_inflate(&state->s, Z_FULL_FLUSH);
if (r != Z_OK && r != Z_STREAM_END)
fatal("inflate returned %d msg: %s\n\r", r, state->s.msg);
len = state->s.next_out - (unsigned char *)dst;
} else {
/* uncompressed image */
len = min(state->s.avail_in, (unsigned)dstlen);
memcpy(dst, state->s.next_in, len);
state->s.next_in += len;
state->s.avail_in -= len;
}
return len;
}
/**
* gunzip_exactly - extract a fixed number of bytes from a gzip data stream
* @state: gzip state structure previously initialized by gunzip_start()
* @dst: buffer to store extracted data
* @dstlen: number of bytes to extract
*
* This function extracts exactly @dstlen bytes from the data stream
* previously associated with @state by gunzip_start(), decompressing
* if necessary.
*
* If there are less @dstlen bytes available in the data stream, or if
* any other errors occur, such as a corrupted compressed stream, an
* error is printed an the platform's exit() function is called.
*/
void gunzip_exactly(struct gunzip_state *state, void *dst, int dstlen)
{
int len;
len = gunzip_partial(state, dst, dstlen);
if (len < dstlen)
fatal("\n\rgunzip_exactly: ran out of data!"
" Wanted %d, got %d.\n\r", dstlen, len);
}
/**
* gunzip_discard - discard bytes from a gzip data stream
* @state: gzip state structure previously initialized by gunzip_start()
* @len: number of bytes to discard
*
* This function extracts, then discards exactly @len bytes from the
* data stream previously associated with @state by gunzip_start().
* Subsequent gunzip_partial(), gunzip_exactly() or gunzip_finish()
* calls will extract the data following the discarded bytes in the
* data stream.
*
* If there are less @len bytes available in the data stream, or if
* any other errors occur, such as a corrupted compressed stream, an
* error is printed an the platform's exit() function is called.
*/
void gunzip_discard(struct gunzip_state *state, int len)
{
static char discard_buf[128];
while (len > sizeof(discard_buf)) {
gunzip_exactly(state, discard_buf, sizeof(discard_buf));
len -= sizeof(discard_buf);
}
if (len > 0)
gunzip_exactly(state, discard_buf, len);
}
/**
* gunzip_finish - extract all remaining bytes from a gzip data stream
* @state: gzip state structure previously initialized by gunzip_start()
* @dst: buffer to store extracted data
* @dstlen: maximum number of bytes to extract
*
* This function extracts all remaining data, or at most @dstlen
* bytes, from the stream previously associated with @state by
* gunzip_start(). zlib is then shut down, so it is an error to use
* any of the functions in this file on @state until it is
* re-initialized with another call to gunzip_start().
*
* If any errors occur, such as a corrupted compressed stream, an
* error is printed an the platform's exit() function is called.
*/
int gunzip_finish(struct gunzip_state *state, void *dst, int dstlen)
{
int len;
len = gunzip_partial(state, dst, dstlen);
if (state->s.workspace) {
zlib_inflateEnd(&state->s);
}
return len;
}
|