2007-03-05 06:24:52 +03:00
/*
* 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
2007-03-14 08:32:17 +03:00
/**
* 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 .
*/
2007-03-05 06:24:52 +03:00
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 ;
2007-03-21 18:02:44 +03:00
if ( zlib_inflate_workspacesize ( ) > sizeof ( state - > scratch ) )
fatal ( " insufficient scratch space for gunzip \n \r " ) ;
2007-03-05 06:24:52 +03:00
/* skip header */
hdrlen = 10 ;
flags = hdr [ 3 ] ;
2007-03-21 18:02:44 +03:00
if ( hdr [ 2 ] ! = Z_DEFLATED | | ( flags & RESERVED ) ! = 0 )
fatal ( " bad gzipped data \n \r " ) ;
2007-03-05 06:24:52 +03:00
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 ;
2007-03-21 18:02:44 +03:00
if ( hdrlen > = srclen )
fatal ( " gunzip_start: ran out of data in header \n \r " ) ;
2007-03-05 06:24:52 +03:00
r = zlib_inflateInit2 ( & state - > s , - MAX_WBITS ) ;
2007-03-21 18:02:44 +03:00
if ( r ! = Z_OK )
fatal ( " inflateInit2 returned %d \n \r " , r ) ;
2007-03-05 06:24:52 +03:00
}
2007-09-22 03:03:34 +04:00
state - > s . total_in = hdrlen ;
2007-03-05 06:24:52 +03:00
state - > s . next_in = src + hdrlen ;
state - > s . avail_in = srclen - hdrlen ;
}
2007-03-14 08:32:17 +03:00
/**
* 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 .
*/
2007-03-05 06:24:52 +03:00
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 ) ;
2007-03-21 18:02:44 +03:00
if ( r ! = Z_OK & & r ! = Z_STREAM_END )
fatal ( " inflate returned %d msg: %s \n \r " , r , state - > s . msg ) ;
2007-03-05 06:24:52 +03:00
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 ;
}
2007-03-14 08:32:17 +03:00
/**
* 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 .
*/
2007-03-05 06:24:52 +03:00
void gunzip_exactly ( struct gunzip_state * state , void * dst , int dstlen )
{
int len ;
len = gunzip_partial ( state , dst , dstlen ) ;
2007-03-21 18:02:44 +03:00
if ( len < dstlen )
2007-04-11 12:32:36 +04:00
fatal ( " \n \r gunzip_exactly: ran out of data! "
" Wanted %d, got %d. \n \r " , dstlen , len ) ;
2007-03-05 06:24:52 +03:00
}
2007-03-14 08:32:17 +03:00
/**
* 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 .
*/
2007-03-05 06:24:52 +03:00
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 ) ;
}
2007-03-14 08:32:17 +03:00
/**
* 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 .
*/
2007-03-05 06:24:52 +03:00
int gunzip_finish ( struct gunzip_state * state , void * dst , int dstlen )
{
int len ;
2007-09-22 03:03:52 +04:00
len = gunzip_partial ( state , dst , dstlen ) ;
2007-03-05 06:24:52 +03:00
if ( state - > s . workspace ) {
zlib_inflateEnd ( & state - > s ) ;
}
return len ;
}