2012-01-26 12:56:22 +04:00
/**
2019-09-30 18:04:54 +03:00
* xzlib . c : front end for the transparent support of lzma compression
2012-01-26 12:56:22 +04:00
* at the I / O layer , based on an example file from lzma project
*
* See Copyright for the status of this software .
*
* Anders F Bjorklund < afb @ users . sourceforge . net >
*/
# define IN_LIBXML
# include "libxml.h"
2015-11-03 10:46:29 +03:00
# ifdef LIBXML_LZMA_ENABLED
2012-01-26 12:56:22 +04:00
# include <string.h>
2022-03-02 02:29:17 +03:00
# include <stdlib.h>
2012-01-26 12:56:22 +04:00
# include <errno.h>
# ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
# endif
# ifdef HAVE_FCNTL_H
# include <fcntl.h>
# endif
# ifdef HAVE_UNISTD_H
# include <unistd.h>
2022-11-22 10:20:53 +03:00
# elif defined (_WIN32)
# include <io.h>
2012-01-26 12:56:22 +04:00
# endif
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2012-01-26 12:56:22 +04:00
# include <zlib.h>
# endif
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_LZMA_ENABLED
2012-01-26 12:56:22 +04:00
# include <lzma.h>
2015-11-03 10:46:29 +03:00
# endif
2012-01-26 12:56:22 +04:00
2022-08-26 02:22:33 +03:00
# include "private/xzlib.h"
2012-05-15 05:38:13 +04:00
# include <libxml/xmlmemory.h>
2011-09-19 11:53:20 +04:00
/* values for xz_state how */
2012-01-26 12:56:22 +04:00
# define LOOK 0 /* look for a gzip/lzma header */
# define COPY 1 /* copy input directly */
# define GZIP 2 /* decompress a gzip stream */
# define LZMA 3 /* decompress a lzma stream */
2011-09-19 11:53:20 +04:00
/* internal lzma file state data structure */
typedef struct {
2012-01-26 12:56:22 +04:00
int mode ; /* see lzma modes above */
int fd ; /* file descriptor */
char * path ; /* path or fd for error messages */
uint64_t pos ; /* current position in uncompressed data */
2012-04-02 13:52:20 +04:00
unsigned int size ; /* buffer size, zero if not allocated yet */
unsigned int want ; /* requested buffer size, default is BUFSIZ */
2012-01-26 12:56:22 +04:00
unsigned char * in ; /* input buffer */
unsigned char * out ; /* output buffer (double-sized when reading) */
unsigned char * next ; /* next output data to deliver or write */
2012-04-02 13:52:20 +04:00
unsigned int have ; /* amount of output data unused at next */
2012-01-26 12:56:22 +04:00
int eof ; /* true if end of input file reached */
uint64_t start ; /* where the lzma data started, for rewinding */
uint64_t raw ; /* where the raw data started, for seeking */
int how ; /* 0: get header, 1: copy, 2: decompress */
int direct ; /* true if last read direct, false if lzma */
/* seek request */
uint64_t skip ; /* amount to skip (already rewound if backwards) */
int seek ; /* true if seek request pending */
/* error information */
int err ; /* error code */
char * msg ; /* error message */
/* lzma stream */
2019-09-30 18:04:54 +03:00
int init ; /* is the inflate stream initialized */
2012-01-26 12:56:22 +04:00
lzma_stream strm ; /* stream structure in-place (not a pointer) */
char padding1 [ 32 ] ; /* padding allowing to cope with possible
extensions of above structure without
too much side effect */
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2012-01-26 12:56:22 +04:00
/* zlib inflate or deflate stream */
z_stream zstrm ; /* stream structure in-place (not a pointer) */
2011-09-19 11:53:20 +04:00
# endif
2012-01-26 12:56:22 +04:00
char padding2 [ 32 ] ; /* padding allowing to cope with possible
extensions of above structure without
too much side effect */
2011-09-19 11:53:20 +04:00
} xz_state , * xz_statep ;
2012-01-26 12:56:22 +04:00
static void
xz_error ( xz_statep state , int err , const char * msg )
2011-09-19 11:53:20 +04:00
{
/* free previously allocated message and clear */
if ( state - > msg ! = NULL ) {
if ( state - > err ! = LZMA_MEM_ERROR )
2012-05-15 05:38:13 +04:00
xmlFree ( state - > msg ) ;
2011-09-19 11:53:20 +04:00
state - > msg = NULL ;
}
/* set error code, and if no message, then done */
state - > err = err ;
if ( msg = = NULL )
return ;
/* for an out of memory error, save as static string */
if ( err = = LZMA_MEM_ERROR ) {
2012-01-26 12:56:22 +04:00
state - > msg = ( char * ) msg ;
2011-09-19 11:53:20 +04:00
return ;
}
/* construct error message with path */
2012-01-26 12:56:22 +04:00
if ( ( state - > msg =
2012-05-15 05:38:13 +04:00
xmlMalloc ( strlen ( state - > path ) + strlen ( msg ) + 3 ) ) = = NULL ) {
2011-09-19 11:53:20 +04:00
state - > err = LZMA_MEM_ERROR ;
2012-01-26 12:56:22 +04:00
state - > msg = ( char * ) " out of memory " ;
2011-09-19 11:53:20 +04:00
return ;
}
strcpy ( state - > msg , state - > path ) ;
strcat ( state - > msg , " : " ) ;
strcat ( state - > msg , msg ) ;
return ;
}
2012-01-26 12:56:22 +04:00
static void
xz_reset ( xz_statep state )
2011-09-19 11:53:20 +04:00
{
2012-01-26 12:56:22 +04:00
state - > have = 0 ; /* no output data available */
state - > eof = 0 ; /* not at end of file */
state - > how = LOOK ; /* look for gzip header */
state - > direct = 1 ; /* default for empty file */
state - > seek = 0 ; /* no seek request pending */
xz_error ( state , LZMA_OK , NULL ) ; /* clear error */
state - > pos = 0 ; /* no uncompressed data yet */
state - > strm . avail_in = 0 ; /* no input data yet */
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2012-01-26 12:56:22 +04:00
state - > zstrm . avail_in = 0 ; /* no input data yet */
2011-09-19 11:53:20 +04:00
# endif
}
2012-01-26 12:56:22 +04:00
static xzFile
xz_open ( const char * path , int fd , const char * mode ATTRIBUTE_UNUSED )
2011-09-19 11:53:20 +04:00
{
xz_statep state ;
2023-03-14 16:19:03 +03:00
off_t offset ;
2011-09-19 11:53:20 +04:00
/* allocate xzFile structure to return */
2012-05-15 05:38:13 +04:00
state = xmlMalloc ( sizeof ( xz_state ) ) ;
2011-09-19 11:53:20 +04:00
if ( state = = NULL )
return NULL ;
state - > size = 0 ; /* no buffers allocated yet */
state - > want = BUFSIZ ; /* requested buffer size */
state - > msg = NULL ; /* no error message yet */
2012-05-15 05:38:13 +04:00
state - > init = 0 ; /* initialization of zlib data */
2011-09-19 11:53:20 +04:00
2012-01-26 12:56:22 +04:00
/* save the path name for error messages */
2012-05-15 05:38:13 +04:00
state - > path = xmlMalloc ( strlen ( path ) + 1 ) ;
2011-09-19 11:53:20 +04:00
if ( state - > path = = NULL ) {
2012-05-15 05:38:13 +04:00
xmlFree ( state ) ;
2011-09-19 11:53:20 +04:00
return NULL ;
}
strcpy ( state - > path , path ) ;
/* open the file with the appropriate mode (or just use fd) */
2012-01-26 12:56:22 +04:00
state - > fd = fd ! = - 1 ? fd : open ( path ,
2011-09-19 11:53:20 +04:00
# ifdef O_LARGEFILE
2012-01-26 12:56:22 +04:00
O_LARGEFILE |
2011-09-19 11:53:20 +04:00
# endif
# ifdef O_BINARY
2012-01-26 12:56:22 +04:00
O_BINARY |
2011-09-19 11:53:20 +04:00
# endif
2012-01-26 12:56:22 +04:00
O_RDONLY , 0666 ) ;
2011-09-19 11:53:20 +04:00
if ( state - > fd = = - 1 ) {
2012-05-15 05:38:13 +04:00
xmlFree ( state - > path ) ;
xmlFree ( state ) ;
2011-09-19 11:53:20 +04:00
return NULL ;
}
/* save the current position for rewinding (only if reading) */
2023-03-14 16:19:03 +03:00
offset = lseek ( state - > fd , 0 , SEEK_CUR ) ;
if ( offset = = - 1 )
2012-01-26 12:56:22 +04:00
state - > start = 0 ;
2023-03-14 16:19:03 +03:00
else
state - > start = offset ;
2011-09-19 11:53:20 +04:00
/* initialize stream */
xz_reset ( state ) ;
/* return stream */
2012-01-26 12:56:22 +04:00
return ( xzFile ) state ;
2011-09-19 11:53:20 +04:00
}
2013-05-10 10:01:46 +04:00
static int
xz_compressed ( xzFile f ) {
xz_statep state ;
if ( f = = NULL )
return ( - 1 ) ;
state = ( xz_statep ) f ;
if ( state - > init < = 0 )
return ( - 1 ) ;
switch ( state - > how ) {
case COPY :
return ( 0 ) ;
case GZIP :
2023-12-19 19:05:08 +03:00
# ifdef LIBXML_ZLIB_ENABLED
/* Don't use lzma for gzip */
return ( 0 ) ;
# else
return ( 1 ) ;
# endif
2013-05-10 10:01:46 +04:00
case LZMA :
return ( 1 ) ;
}
return ( - 1 ) ;
}
2012-01-26 12:56:22 +04:00
xzFile
__libxml2_xzopen ( const char * path , const char * mode )
2011-09-19 11:53:20 +04:00
{
return xz_open ( path , - 1 , mode ) ;
}
2012-01-26 12:56:22 +04:00
xzFile
2023-12-23 06:03:41 +03:00
__libxml2_xzdopen ( const char * path , int fd , const char * mode )
2011-09-19 11:53:20 +04:00
{
2023-12-23 06:03:41 +03:00
return xz_open ( path , fd , mode ) ;
2011-09-19 11:53:20 +04:00
}
2012-01-26 12:56:22 +04:00
static int
2012-04-02 13:52:20 +04:00
xz_load ( xz_statep state , unsigned char * buf , unsigned int len ,
unsigned int * have )
2011-09-19 11:53:20 +04:00
{
int ret ;
* have = 0 ;
do {
ret = read ( state - > fd , buf + * have , len - * have ) ;
if ( ret < = 0 )
break ;
* have + = ret ;
} while ( * have < len ) ;
if ( ret < 0 ) {
xz_error ( state , - 1 , strerror ( errno ) ) ;
return - 1 ;
}
if ( ret = = 0 )
state - > eof = 1 ;
return 0 ;
}
2012-01-26 12:56:22 +04:00
static int
xz_avail ( xz_statep state )
2011-09-19 11:53:20 +04:00
{
lzma_stream * strm = & ( state - > strm ) ;
if ( state - > err ! = LZMA_OK )
return - 1 ;
if ( state - > eof = = 0 ) {
2012-05-07 14:41:42 +04:00
/* avail_in is size_t, which is not necessary sizeof(unsigned) */
unsigned tmp = strm - > avail_in ;
if ( xz_load ( state , state - > in , state - > size , & tmp ) = = - 1 ) {
strm - > avail_in = tmp ;
2011-09-19 11:53:20 +04:00
return - 1 ;
2012-05-07 14:41:42 +04:00
}
strm - > avail_in = tmp ;
2011-09-19 11:53:20 +04:00
strm - > next_in = state - > in ;
}
return 0 ;
}
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2013-11-28 19:21:23 +04:00
static int
xz_avail_zstrm ( xz_statep state )
{
int ret ;
state - > strm . avail_in = state - > zstrm . avail_in ;
state - > strm . next_in = state - > zstrm . next_in ;
ret = xz_avail ( state ) ;
state - > zstrm . avail_in = ( uInt ) state - > strm . avail_in ;
state - > zstrm . next_in = ( Bytef * ) state - > strm . next_in ;
return ret ;
}
# endif
2011-09-19 11:53:20 +04:00
static int
is_format_xz ( xz_statep state )
{
lzma_stream * strm = & ( state - > strm ) ;
2012-01-26 12:56:22 +04:00
return strm - > avail_in > = 6 & & memcmp ( state - > in , " \375 7zXZ " , 6 ) = = 0 ;
2011-09-19 11:53:20 +04:00
}
static int
is_format_lzma ( xz_statep state )
{
lzma_stream * strm = & ( state - > strm ) ;
2012-01-26 12:56:22 +04:00
lzma_filter filter ;
lzma_options_lzma * opt ;
uint32_t dict_size ;
uint64_t uncompressed_size ;
size_t i ;
if ( strm - > avail_in < 13 )
return 0 ;
filter . id = LZMA_FILTER_LZMA1 ;
if ( lzma_properties_decode ( & filter , NULL , state - > in , 5 ) ! = LZMA_OK )
return 0 ;
opt = filter . options ;
dict_size = opt - > dict_size ;
2012-05-15 06:45:05 +04:00
free ( opt ) ; /* we can't use xmlFree on a string returned by zlib */
2012-01-26 12:56:22 +04:00
/* A hack to ditch tons of false positives: We allow only dictionary
* sizes that are 2 ^ n or 2 ^ n + 2 ^ ( n - 1 ) or UINT32_MAX . LZMA_Alone
* created only files with 2 ^ n , but accepts any dictionary size .
* If someone complains , this will be reconsidered .
*/
if ( dict_size ! = UINT32_MAX ) {
2023-12-19 21:47:07 +03:00
uint32_t d ;
2012-01-26 12:56:22 +04:00
2023-12-19 21:47:07 +03:00
if ( dict_size = = 0 )
return 0 ;
d = dict_size - 1 ;
2012-01-26 12:56:22 +04:00
d | = d > > 2 ;
d | = d > > 3 ;
d | = d > > 4 ;
d | = d > > 8 ;
d | = d > > 16 ;
+ + d ;
if ( d ! = dict_size | | dict_size = = 0 )
return 0 ;
}
/* Another hack to ditch false positives: Assume that if the
* uncompressed size is known , it must be less than 256 GiB .
* Again , if someone complains , this will be reconsidered .
*/
uncompressed_size = 0 ;
for ( i = 0 ; i < 8 ; + + i )
uncompressed_size | = ( uint64_t ) ( state - > in [ 5 + i ] ) < < ( i * 8 ) ;
if ( uncompressed_size ! = UINT64_MAX
& & uncompressed_size > ( UINT64_C ( 1 ) < < 38 ) )
return 0 ;
return 1 ;
2011-09-19 11:53:20 +04:00
}
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2012-01-26 12:56:22 +04:00
2011-09-19 11:53:20 +04:00
/* Get next byte from input, or -1 if end or error. */
# define NEXT() ((strm->avail_in == 0 && xz_avail(state) == -1) ? -1 : \
( strm - > avail_in = = 0 ? - 1 : \
( strm - > avail_in - - , * ( strm - > next_in ) + + ) ) )
2013-11-28 19:21:23 +04:00
/* Same thing, but from zstrm */
# define NEXTZ() ((strm->avail_in == 0 && xz_avail_zstrm(state) == -1) ? -1 : \
( strm - > avail_in = = 0 ? - 1 : \
( strm - > avail_in - - , * ( strm - > next_in ) + + ) ) )
2011-09-19 11:53:20 +04:00
/* Get a four-byte little-endian integer and return 0 on success and the value
in * ret . Otherwise - 1 is returned and * ret is not modified . */
2012-01-26 12:56:22 +04:00
static int
gz_next4 ( xz_statep state , unsigned long * ret )
2011-09-19 11:53:20 +04:00
{
int ch ;
unsigned long val ;
z_streamp strm = & ( state - > zstrm ) ;
2013-11-28 19:21:23 +04:00
val = NEXTZ ( ) ;
val + = ( unsigned ) NEXTZ ( ) < < 8 ;
val + = ( unsigned long ) NEXTZ ( ) < < 16 ;
ch = NEXTZ ( ) ;
2011-09-19 11:53:20 +04:00
if ( ch = = - 1 )
return - 1 ;
2012-01-26 12:56:22 +04:00
val + = ( unsigned long ) ch < < 24 ;
2011-09-19 11:53:20 +04:00
* ret = val ;
return 0 ;
}
# endif
2012-01-26 12:56:22 +04:00
static int
xz_head ( xz_statep state )
2011-09-19 11:53:20 +04:00
{
lzma_stream * strm = & ( state - > strm ) ;
lzma_stream init = LZMA_STREAM_INIT ;
int flags ;
unsigned len ;
2022-02-22 21:57:12 +03:00
/* Avoid unused variable warning if features are disabled. */
( void ) flags ;
( void ) len ;
2011-09-19 11:53:20 +04:00
/* allocate read buffers and inflate memory */
if ( state - > size = = 0 ) {
/* allocate buffers */
2012-05-15 05:38:13 +04:00
state - > in = xmlMalloc ( state - > want ) ;
state - > out = xmlMalloc ( state - > want < < 1 ) ;
2011-09-19 11:53:20 +04:00
if ( state - > in = = NULL | | state - > out = = NULL ) {
if ( state - > out ! = NULL )
2012-05-15 05:38:13 +04:00
xmlFree ( state - > out ) ;
2011-09-19 11:53:20 +04:00
if ( state - > in ! = NULL )
2012-05-15 05:38:13 +04:00
xmlFree ( state - > in ) ;
2011-09-19 11:53:20 +04:00
xz_error ( state , LZMA_MEM_ERROR , " out of memory " ) ;
return - 1 ;
}
state - > size = state - > want ;
/* allocate decoder memory */
state - > strm = init ;
state - > strm . avail_in = 0 ;
state - > strm . next_in = NULL ;
2017-09-07 19:36:01 +03:00
if ( lzma_auto_decoder ( & state - > strm , 100000000 , 0 ) ! = LZMA_OK ) {
2012-05-15 05:38:13 +04:00
xmlFree ( state - > out ) ;
xmlFree ( state - > in ) ;
2011-09-19 11:53:20 +04:00
state - > size = 0 ;
xz_error ( state , LZMA_MEM_ERROR , " out of memory " ) ;
return - 1 ;
2012-01-26 12:56:22 +04:00
}
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2011-09-19 11:53:20 +04:00
/* allocate inflate memory */
state - > zstrm . zalloc = Z_NULL ;
state - > zstrm . zfree = Z_NULL ;
state - > zstrm . opaque = Z_NULL ;
state - > zstrm . avail_in = 0 ;
state - > zstrm . next_in = Z_NULL ;
2012-05-15 05:38:13 +04:00
if ( state - > init = = 0 ) {
if ( inflateInit2 ( & ( state - > zstrm ) , - 15 ) ! = Z_OK ) { /* raw inflate */
xmlFree ( state - > out ) ;
xmlFree ( state - > in ) ;
state - > size = 0 ;
xz_error ( state , LZMA_MEM_ERROR , " out of memory " ) ;
return - 1 ;
}
state - > init = 1 ;
2011-09-19 11:53:20 +04:00
}
# endif
}
/* get some data in the input buffer */
if ( strm - > avail_in = = 0 ) {
if ( xz_avail ( state ) = = - 1 )
return - 1 ;
if ( strm - > avail_in = = 0 )
return 0 ;
}
2012-01-26 12:56:22 +04:00
/* look for the xz magic header bytes */
2011-09-19 11:53:20 +04:00
if ( is_format_xz ( state ) | | is_format_lzma ( state ) ) {
2012-01-26 12:56:22 +04:00
state - > how = LZMA ;
state - > direct = 0 ;
return 0 ;
2011-09-19 11:53:20 +04:00
}
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2012-01-26 12:56:22 +04:00
/* look for the gzip magic header bytes 31 and 139 */
2011-09-19 11:53:20 +04:00
if ( strm - > next_in [ 0 ] = = 31 ) {
strm - > avail_in - - ;
strm - > next_in + + ;
if ( strm - > avail_in = = 0 & & xz_avail ( state ) = = - 1 )
return - 1 ;
if ( strm - > avail_in & & strm - > next_in [ 0 ] = = 139 ) {
/* we have a gzip header, woo hoo! */
strm - > avail_in - - ;
strm - > next_in + + ;
/* skip rest of header */
2012-01-26 12:56:22 +04:00
if ( NEXT ( ) ! = 8 ) { /* compression method */
xz_error ( state , LZMA_DATA_ERROR ,
" unknown compression method " ) ;
2011-09-19 11:53:20 +04:00
return - 1 ;
}
flags = NEXT ( ) ;
2012-01-26 12:56:22 +04:00
if ( flags & 0xe0 ) { /* reserved flag bits */
xz_error ( state , LZMA_DATA_ERROR ,
" unknown header flags set " ) ;
2011-09-19 11:53:20 +04:00
return - 1 ;
}
2012-01-26 12:56:22 +04:00
NEXT ( ) ; /* modification time */
2011-09-19 11:53:20 +04:00
NEXT ( ) ;
NEXT ( ) ;
NEXT ( ) ;
2012-01-26 12:56:22 +04:00
NEXT ( ) ; /* extra flags */
NEXT ( ) ; /* operating system */
if ( flags & 4 ) { /* extra field */
len = ( unsigned ) NEXT ( ) ;
len + = ( unsigned ) NEXT ( ) < < 8 ;
2011-09-19 11:53:20 +04:00
while ( len - - )
if ( NEXT ( ) < 0 )
break ;
}
2012-01-26 12:56:22 +04:00
if ( flags & 8 ) /* file name */
while ( NEXT ( ) > 0 ) ;
if ( flags & 16 ) /* comment */
while ( NEXT ( ) > 0 ) ;
if ( flags & 2 ) { /* header crc */
2011-09-19 11:53:20 +04:00
NEXT ( ) ;
NEXT ( ) ;
}
/* an unexpected end of file is not checked for here -- it will be
2012-01-26 12:56:22 +04:00
* noticed on the first request for uncompressed data */
2011-09-19 11:53:20 +04:00
/* set up for decompression */
inflateReset ( & state - > zstrm ) ;
state - > zstrm . adler = crc32 ( 0L , Z_NULL , 0 ) ;
state - > how = GZIP ;
state - > direct = 0 ;
return 0 ;
2012-01-26 12:56:22 +04:00
} else {
2011-09-19 11:53:20 +04:00
/* not a gzip file -- save first byte (31) and fall to raw i/o */
state - > out [ 0 ] = 31 ;
state - > have = 1 ;
}
}
# endif
/* doing raw i/o, save start of raw data for seeking, copy any leftover
2012-01-26 12:56:22 +04:00
* input to output - - this assumes that the output buffer is larger than
* the input buffer , which also assures space for gzungetc ( ) */
2011-09-19 11:53:20 +04:00
state - > raw = state - > pos ;
state - > next = state - > out ;
if ( strm - > avail_in ) {
memcpy ( state - > next + state - > have , strm - > next_in , strm - > avail_in ) ;
state - > have + = strm - > avail_in ;
strm - > avail_in = 0 ;
}
state - > how = COPY ;
state - > direct = 1 ;
return 0 ;
}
2012-01-26 12:56:22 +04:00
static int
xz_decomp ( xz_statep state )
2011-09-19 11:53:20 +04:00
{
int ret ;
unsigned had ;
unsigned long crc , len ;
lzma_stream * strm = & ( state - > strm ) ;
lzma_action action = LZMA_RUN ;
2022-02-22 21:57:12 +03:00
/* Avoid unused variable warning if features are disabled. */
( void ) crc ;
( void ) len ;
2011-09-19 11:53:20 +04:00
/* fill output buffer up to end of deflate stream */
had = strm - > avail_out ;
do {
/* get more input for inflate() */
if ( strm - > avail_in = = 0 & & xz_avail ( state ) = = - 1 )
return - 1 ;
if ( strm - > avail_in = = 0 ) {
xz_error ( state , LZMA_DATA_ERROR , " unexpected end of file " ) ;
return - 1 ;
}
if ( state - > eof )
action = LZMA_FINISH ;
2012-01-26 12:56:22 +04:00
2011-09-19 11:53:20 +04:00
/* decompress and handle errors */
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2011-09-19 11:53:20 +04:00
if ( state - > how = = GZIP ) {
2012-01-26 12:56:22 +04:00
state - > zstrm . avail_in = ( uInt ) state - > strm . avail_in ;
state - > zstrm . next_in = ( Bytef * ) state - > strm . next_in ;
state - > zstrm . avail_out = ( uInt ) state - > strm . avail_out ;
state - > zstrm . next_out = ( Bytef * ) state - > strm . next_out ;
ret = inflate ( & state - > zstrm , Z_NO_FLUSH ) ;
if ( ret = = Z_STREAM_ERROR | | ret = = Z_NEED_DICT ) {
xz_error ( state , Z_STREAM_ERROR ,
" internal error: inflate stream corrupt " ) ;
return - 1 ;
}
2018-07-30 14:14:11 +03:00
/*
* FIXME : Remapping a couple of error codes and falling through
* to the LZMA error handling looks fragile .
*/
2012-01-26 12:56:22 +04:00
if ( ret = = Z_MEM_ERROR )
ret = LZMA_MEM_ERROR ;
if ( ret = = Z_DATA_ERROR )
ret = LZMA_DATA_ERROR ;
if ( ret = = Z_STREAM_END )
ret = LZMA_STREAM_END ;
state - > strm . avail_in = state - > zstrm . avail_in ;
state - > strm . next_in = state - > zstrm . next_in ;
state - > strm . avail_out = state - > zstrm . avail_out ;
state - > strm . next_out = state - > zstrm . next_out ;
} else /* state->how == LZMA */
2011-09-19 11:53:20 +04:00
# endif
2012-01-26 12:56:22 +04:00
ret = lzma_code ( strm , action ) ;
2011-09-19 11:53:20 +04:00
if ( ret = = LZMA_MEM_ERROR ) {
xz_error ( state , LZMA_MEM_ERROR , " out of memory " ) ;
return - 1 ;
}
if ( ret = = LZMA_DATA_ERROR ) {
xz_error ( state , LZMA_DATA_ERROR , " compressed data error " ) ;
return - 1 ;
}
2015-11-03 10:31:25 +03:00
if ( ret = = LZMA_PROG_ERROR ) {
xz_error ( state , LZMA_PROG_ERROR , " compression error " ) ;
return - 1 ;
}
2018-07-30 14:14:11 +03:00
if ( ( state - > how ! = GZIP ) & &
( ret ! = LZMA_OK ) & & ( ret ! = LZMA_STREAM_END ) ) {
xz_error ( state , ret , " lzma error " ) ;
return - 1 ;
}
2011-09-19 11:53:20 +04:00
} while ( strm - > avail_out & & ret ! = LZMA_STREAM_END ) ;
/* update available output and crc check value */
state - > have = had - strm - > avail_out ;
state - > next = strm - > next_out - state - > have ;
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2012-01-26 12:56:22 +04:00
state - > zstrm . adler =
crc32 ( state - > zstrm . adler , state - > next , state - > have ) ;
2011-09-19 11:53:20 +04:00
# endif
if ( ret = = LZMA_STREAM_END ) {
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2011-09-19 11:53:20 +04:00
if ( state - > how = = GZIP ) {
2012-01-26 12:56:22 +04:00
if ( gz_next4 ( state , & crc ) = = - 1 | | gz_next4 ( state , & len ) = = - 1 ) {
xz_error ( state , LZMA_DATA_ERROR , " unexpected end of file " ) ;
return - 1 ;
}
if ( crc ! = state - > zstrm . adler ) {
xz_error ( state , LZMA_DATA_ERROR , " incorrect data check " ) ;
return - 1 ;
}
if ( len ! = ( state - > zstrm . total_out & 0xffffffffL ) ) {
xz_error ( state , LZMA_DATA_ERROR , " incorrect length check " ) ;
return - 1 ;
}
state - > strm . avail_in = 0 ;
state - > strm . next_in = NULL ;
state - > strm . avail_out = 0 ;
state - > strm . next_out = NULL ;
} else
2011-09-19 11:53:20 +04:00
# endif
2012-01-26 12:56:22 +04:00
if ( strm - > avail_in ! = 0 | | ! state - > eof ) {
2011-09-19 11:53:20 +04:00
xz_error ( state , LZMA_DATA_ERROR , " trailing garbage " ) ;
return - 1 ;
}
state - > how = LOOK ; /* ready for next stream, once have is 0 (leave
2012-01-26 12:56:22 +04:00
* state - > direct unchanged to remember how ) */
2011-09-19 11:53:20 +04:00
}
/* good decompression */
return 0 ;
}
2012-01-26 12:56:22 +04:00
static int
xz_make ( xz_statep state )
2011-09-19 11:53:20 +04:00
{
lzma_stream * strm = & ( state - > strm ) ;
2012-01-26 12:56:22 +04:00
if ( state - > how = = LOOK ) { /* look for lzma / gzip header */
2011-09-19 11:53:20 +04:00
if ( xz_head ( state ) = = - 1 )
return - 1 ;
2012-01-26 12:56:22 +04:00
if ( state - > have ) /* got some data from xz_head() */
2011-09-19 11:53:20 +04:00
return 0 ;
}
2012-01-26 12:56:22 +04:00
if ( state - > how = = COPY ) { /* straight copy */
if ( xz_load ( state , state - > out , state - > size < < 1 , & ( state - > have ) ) = =
- 1 )
2011-09-19 11:53:20 +04:00
return - 1 ;
state - > next = state - > out ;
2012-01-26 12:56:22 +04:00
} else if ( state - > how = = LZMA | | state - > how = = GZIP ) { /* decompress */
2011-09-19 11:53:20 +04:00
strm - > avail_out = state - > size < < 1 ;
strm - > next_out = state - > out ;
if ( xz_decomp ( state ) = = - 1 )
return - 1 ;
}
return 0 ;
}
2012-01-26 12:56:22 +04:00
static int
xz_skip ( xz_statep state , uint64_t len )
2011-09-19 11:53:20 +04:00
{
unsigned n ;
/* skip over len bytes or reach end-of-file, whichever comes first */
while ( len )
/* skip over whatever is in output buffer */
if ( state - > have ) {
2012-01-26 12:56:22 +04:00
n = ( uint64_t ) state - > have > len ?
( unsigned ) len : state - > have ;
2011-09-19 11:53:20 +04:00
state - > have - = n ;
state - > next + = n ;
state - > pos + = n ;
len - = n ;
}
2012-01-26 12:56:22 +04:00
/* output buffer empty -- return if we're at the end of the input */
2011-09-19 11:53:20 +04:00
else if ( state - > eof & & state - > strm . avail_in = = 0 )
break ;
2012-01-26 12:56:22 +04:00
/* need more data to skip -- load up output buffer */
2011-09-19 11:53:20 +04:00
else {
/* get more output, looking for header if required */
if ( xz_make ( state ) = = - 1 )
return - 1 ;
}
return 0 ;
}
2023-12-19 19:05:08 +03:00
int
__libxml2_xzcompressed ( xzFile f ) {
xz_head ( f ) ;
return xz_compressed ( f ) ;
}
2012-01-26 12:56:22 +04:00
int
__libxml2_xzread ( xzFile file , void * buf , unsigned len )
2011-09-19 11:53:20 +04:00
{
unsigned got , n ;
xz_statep state ;
lzma_stream * strm ;
/* get internal structure */
if ( file = = NULL )
return - 1 ;
2012-01-26 12:56:22 +04:00
state = ( xz_statep ) file ;
2011-09-19 11:53:20 +04:00
strm = & ( state - > strm ) ;
/* check that we're reading and that there's no error */
if ( state - > err ! = LZMA_OK )
return - 1 ;
/* since an int is returned, make sure len fits in one, otherwise return
2012-01-26 12:56:22 +04:00
* with an error ( this avoids the flaw in the interface ) */
if ( ( int ) len < 0 ) {
xz_error ( state , LZMA_BUF_ERROR ,
" requested length does not fit in int " ) ;
2011-09-19 11:53:20 +04:00
return - 1 ;
}
/* if len is zero, avoid unnecessary operations */
if ( len = = 0 )
return 0 ;
/* process a skip request */
if ( state - > seek ) {
state - > seek = 0 ;
if ( xz_skip ( state , state - > skip ) = = - 1 )
return - 1 ;
}
/* get len bytes to buf, or less than len if at the end */
got = 0 ;
do {
/* first just try copying data from the output buffer */
if ( state - > have ) {
n = state - > have > len ? len : state - > have ;
memcpy ( buf , state - > next , n ) ;
state - > next + = n ;
state - > have - = n ;
}
/* output buffer empty -- return if we're at the end of the input */
else if ( state - > eof & & strm - > avail_in = = 0 )
break ;
/* need output data -- for small len or new stream load up our output
2012-01-26 12:56:22 +04:00
* buffer */
2011-09-19 11:53:20 +04:00
else if ( state - > how = = LOOK | | len < ( state - > size < < 1 ) ) {
/* get more output, looking for header if required */
if ( xz_make ( state ) = = - 1 )
return - 1 ;
2012-01-26 12:56:22 +04:00
continue ; /* no progress yet -- go back to memcpy() above */
2011-09-19 11:53:20 +04:00
/* the copy above assures that we will leave with space in the
2012-01-26 12:56:22 +04:00
* output buffer , allowing at least one gzungetc ( ) to succeed */
2011-09-19 11:53:20 +04:00
}
/* large len -- read directly into user buffer */
2012-01-26 12:56:22 +04:00
else if ( state - > how = = COPY ) { /* read directly */
2011-09-19 11:53:20 +04:00
if ( xz_load ( state , buf , len , & n ) = = - 1 )
return - 1 ;
}
/* large len -- decompress directly into user buffer */
2012-01-26 12:56:22 +04:00
else { /* state->how == LZMA */
2011-09-19 11:53:20 +04:00
strm - > avail_out = len ;
strm - > next_out = buf ;
if ( xz_decomp ( state ) = = - 1 )
return - 1 ;
n = state - > have ;
state - > have = 0 ;
}
/* update progress */
len - = n ;
2012-01-26 12:56:22 +04:00
buf = ( char * ) buf + n ;
2011-09-19 11:53:20 +04:00
got + = n ;
state - > pos + = n ;
} while ( len ) ;
/* return number of bytes read into user buffer (will fit in int) */
2012-01-26 12:56:22 +04:00
return ( int ) got ;
2011-09-19 11:53:20 +04:00
}
2012-01-26 12:56:22 +04:00
int
__libxml2_xzclose ( xzFile file )
2011-09-19 11:53:20 +04:00
{
int ret ;
xz_statep state ;
/* get internal structure */
if ( file = = NULL )
return LZMA_DATA_ERROR ;
2012-01-26 12:56:22 +04:00
state = ( xz_statep ) file ;
2011-09-19 11:53:20 +04:00
/* free memory and close file */
if ( state - > size ) {
lzma_end ( & ( state - > strm ) ) ;
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2012-05-15 05:38:13 +04:00
if ( state - > init = = 1 )
inflateEnd ( & ( state - > zstrm ) ) ;
state - > init = 0 ;
2011-09-19 11:53:20 +04:00
# endif
2012-05-15 05:38:13 +04:00
xmlFree ( state - > out ) ;
xmlFree ( state - > in ) ;
2011-09-19 11:53:20 +04:00
}
2012-05-15 05:38:13 +04:00
xmlFree ( state - > path ) ;
2017-09-07 19:55:46 +03:00
if ( ( state - > msg ! = NULL ) & & ( state - > err ! = LZMA_MEM_ERROR ) )
xmlFree ( state - > msg ) ;
2011-09-19 11:53:20 +04:00
ret = close ( state - > fd ) ;
2012-05-15 05:38:13 +04:00
xmlFree ( state ) ;
2011-09-19 11:53:20 +04:00
return ret ? ret : LZMA_OK ;
}
2015-11-03 10:46:29 +03:00
# endif /* LIBXML_LZMA_ENABLED */