Blame libarchive/archive_read_support_format_cab.c

Packit 08bd4c
/*-
Packit 08bd4c
 * Copyright (c) 2010-2012 Michihiro NAKAJIMA
Packit 08bd4c
 * All rights reserved.
Packit 08bd4c
 *
Packit 08bd4c
 * Redistribution and use in source and binary forms, with or without
Packit 08bd4c
 * modification, are permitted provided that the following conditions
Packit 08bd4c
 * are met:
Packit 08bd4c
 * 1. Redistributions of source code must retain the above copyright
Packit 08bd4c
 *    notice, this list of conditions and the following disclaimer.
Packit 08bd4c
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 08bd4c
 *    notice, this list of conditions and the following disclaimer in the
Packit 08bd4c
 *    documentation and/or other materials provided with the distribution.
Packit 08bd4c
 *
Packit 08bd4c
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
Packit 08bd4c
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit 08bd4c
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit 08bd4c
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit 08bd4c
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit 08bd4c
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 08bd4c
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 08bd4c
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 08bd4c
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit 08bd4c
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
#include "archive_platform.h"
Packit 08bd4c
Packit 08bd4c
#ifdef HAVE_ERRNO_H
Packit 08bd4c
#include <errno.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_LIMITS_H
Packit 08bd4c
#include <limits.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_STDLIB_H
Packit 08bd4c
#include <stdlib.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_STRING_H
Packit 08bd4c
#include <string.h>
Packit 08bd4c
#endif
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
#include <zlib.h>
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
#include "archive.h"
Packit 08bd4c
#include "archive_entry.h"
Packit 08bd4c
#include "archive_entry_locale.h"
Packit 08bd4c
#include "archive_private.h"
Packit 08bd4c
#include "archive_read_private.h"
Packit 08bd4c
#include "archive_endian.h"
Packit 08bd4c
Packit 08bd4c
Packit 08bd4c
struct lzx_dec {
Packit 08bd4c
	/* Decoding status. */
Packit 08bd4c
	int     		 state;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Window to see last decoded data, from 32KBi to 2MBi.
Packit 08bd4c
	 */
Packit 08bd4c
	int			 w_size;
Packit 08bd4c
	int			 w_mask;
Packit 08bd4c
	/* Window buffer, which is a loop buffer. */
Packit 08bd4c
	unsigned char		*w_buff;
Packit 08bd4c
	/* The insert position to the window. */
Packit 08bd4c
	int			 w_pos;
Packit 08bd4c
	/* The position where we can copy decoded code from the window. */
Packit 08bd4c
	int     		 copy_pos;
Packit 08bd4c
	/* The length how many bytes we can copy decoded code from
Packit 08bd4c
	 * the window. */
Packit 08bd4c
	int     		 copy_len;
Packit 08bd4c
	/* Translation reversal for x86 processor CALL byte sequence(E8).
Packit 08bd4c
	 * This is used for LZX only. */
Packit 08bd4c
	uint32_t		 translation_size;
Packit 08bd4c
	char			 translation;
Packit 08bd4c
	char			 block_type;
Packit 08bd4c
#define VERBATIM_BLOCK		1
Packit 08bd4c
#define ALIGNED_OFFSET_BLOCK	2
Packit 08bd4c
#define UNCOMPRESSED_BLOCK	3
Packit 08bd4c
	size_t			 block_size;
Packit 08bd4c
	size_t			 block_bytes_avail;
Packit 08bd4c
	/* Repeated offset. */
Packit 08bd4c
	int			 r0, r1, r2;
Packit 08bd4c
	unsigned char		 rbytes[4];
Packit 08bd4c
	int			 rbytes_avail;
Packit 08bd4c
	int			 length_header;
Packit 08bd4c
	int			 position_slot;
Packit 08bd4c
	int			 offset_bits;
Packit 08bd4c
Packit 08bd4c
	struct lzx_pos_tbl {
Packit 08bd4c
		int		 base;
Packit 08bd4c
		int		 footer_bits;
Packit 08bd4c
	}			*pos_tbl;
Packit 08bd4c
	/*
Packit 08bd4c
	 * Bit stream reader.
Packit 08bd4c
	 */
Packit 08bd4c
	struct lzx_br {
Packit 08bd4c
#define CACHE_TYPE		uint64_t
Packit 08bd4c
#define CACHE_BITS		(8 * sizeof(CACHE_TYPE))
Packit 08bd4c
	 	/* Cache buffer. */
Packit 08bd4c
		CACHE_TYPE	 cache_buffer;
Packit 08bd4c
		/* Indicates how many bits avail in cache_buffer. */
Packit 08bd4c
		int		 cache_avail;
Packit 08bd4c
		unsigned char	 odd;
Packit 08bd4c
		char		 have_odd;
Packit 08bd4c
	} br;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Huffman coding.
Packit 08bd4c
	 */
Packit 08bd4c
	struct huffman {
Packit 08bd4c
		int		 len_size;
Packit 08bd4c
		int		 freq[17];
Packit 08bd4c
		unsigned char	*bitlen;
Packit 08bd4c
Packit 08bd4c
		/*
Packit 08bd4c
		 * Use a index table. It's faster than searching a huffman
Packit 08bd4c
		 * coding tree, which is a binary tree. But a use of a large
Packit 08bd4c
		 * index table causes L1 cache read miss many times.
Packit 08bd4c
		 */
Packit 08bd4c
		int		 max_bits;
Packit 08bd4c
		int		 tbl_bits;
Packit 08bd4c
		int		 tree_used;
Packit 08bd4c
		/* Direct access table. */
Packit 08bd4c
		uint16_t	*tbl;
Packit 08bd4c
	}			 at, lt, mt, pt;
Packit 08bd4c
Packit 08bd4c
	int			 loop;
Packit 08bd4c
	int			 error;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
static const int slots[] = {
Packit 08bd4c
	30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
Packit 08bd4c
};
Packit 08bd4c
#define SLOT_BASE	15
Packit 08bd4c
#define SLOT_MAX	21/*->25*/
Packit 08bd4c
Packit 08bd4c
struct lzx_stream {
Packit 08bd4c
	const unsigned char	*next_in;
Packit 08bd4c
	int64_t			 avail_in;
Packit 08bd4c
	int64_t			 total_in;
Packit 08bd4c
	unsigned char		*next_out;
Packit 08bd4c
	int64_t			 avail_out;
Packit 08bd4c
	int64_t			 total_out;
Packit 08bd4c
	struct lzx_dec		*ds;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Cabinet file definitions.
Packit 08bd4c
 */
Packit 08bd4c
/* CFHEADER offset */
Packit 08bd4c
#define CFHEADER_signature	0
Packit 08bd4c
#define CFHEADER_cbCabinet	8
Packit 08bd4c
#define CFHEADER_coffFiles	16
Packit 08bd4c
#define CFHEADER_versionMinor	24
Packit 08bd4c
#define CFHEADER_versionMajor	25
Packit 08bd4c
#define CFHEADER_cFolders	26
Packit 08bd4c
#define CFHEADER_cFiles		28
Packit 08bd4c
#define CFHEADER_flags		30
Packit 08bd4c
#define CFHEADER_setID		32
Packit 08bd4c
#define CFHEADER_iCabinet	34
Packit 08bd4c
#define CFHEADER_cbCFHeader	36
Packit 08bd4c
#define CFHEADER_cbCFFolder	38
Packit 08bd4c
#define CFHEADER_cbCFData	39
Packit 08bd4c
Packit 08bd4c
/* CFFOLDER offset */
Packit 08bd4c
#define CFFOLDER_coffCabStart	0
Packit 08bd4c
#define CFFOLDER_cCFData	4
Packit 08bd4c
#define CFFOLDER_typeCompress	6
Packit 08bd4c
#define CFFOLDER_abReserve	8
Packit 08bd4c
Packit 08bd4c
/* CFFILE offset */
Packit 08bd4c
#define CFFILE_cbFile		0
Packit 08bd4c
#define CFFILE_uoffFolderStart	4
Packit 08bd4c
#define CFFILE_iFolder		8
Packit 08bd4c
#define CFFILE_date_time	10
Packit 08bd4c
#define CFFILE_attribs		14
Packit 08bd4c
Packit 08bd4c
/* CFDATA offset */
Packit 08bd4c
#define CFDATA_csum		0
Packit 08bd4c
#define CFDATA_cbData		4
Packit 08bd4c
#define CFDATA_cbUncomp		6
Packit 08bd4c
Packit 08bd4c
static const char * const compression_name[] = {
Packit 08bd4c
	"NONE",
Packit 08bd4c
	"MSZIP",
Packit 08bd4c
	"Quantum",
Packit 08bd4c
	"LZX",
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
struct cfdata {
Packit 08bd4c
	/* Sum value of this CFDATA. */
Packit 08bd4c
	uint32_t		 sum;
Packit 08bd4c
	uint16_t		 compressed_size;
Packit 08bd4c
	uint16_t		 compressed_bytes_remaining;
Packit 08bd4c
	uint16_t		 uncompressed_size;
Packit 08bd4c
	uint16_t		 uncompressed_bytes_remaining;
Packit 08bd4c
	/* To know how many bytes we have decompressed. */
Packit 08bd4c
	uint16_t		 uncompressed_avail;
Packit 08bd4c
	/* Offset from the beginning of compressed data of this CFDATA */
Packit 08bd4c
	uint16_t		 read_offset;
Packit 08bd4c
	int64_t			 unconsumed;
Packit 08bd4c
	/* To keep memory image of this CFDATA to compute the sum. */
Packit 08bd4c
	size_t			 memimage_size;
Packit 08bd4c
	unsigned char		*memimage;
Packit 08bd4c
	/* Result of calculation of sum. */
Packit 08bd4c
	uint32_t		 sum_calculated;
Packit 08bd4c
	unsigned char		 sum_extra[4];
Packit 08bd4c
	int			 sum_extra_avail;
Packit 08bd4c
	const void		*sum_ptr;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
struct cffolder {
Packit 08bd4c
	uint32_t		 cfdata_offset_in_cab;
Packit 08bd4c
	uint16_t		 cfdata_count;
Packit 08bd4c
	uint16_t		 comptype;
Packit 08bd4c
#define COMPTYPE_NONE		0x0000
Packit 08bd4c
#define COMPTYPE_MSZIP		0x0001
Packit 08bd4c
#define COMPTYPE_QUANTUM	0x0002
Packit 08bd4c
#define COMPTYPE_LZX		0x0003
Packit 08bd4c
	uint16_t		 compdata;
Packit 08bd4c
	const char		*compname;
Packit 08bd4c
	/* At the time reading CFDATA */
Packit 08bd4c
	struct cfdata		 cfdata;
Packit 08bd4c
	int			 cfdata_index;
Packit 08bd4c
	/* Flags to mark progress of decompression. */
Packit 08bd4c
	char			 decompress_init;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
struct cffile {
Packit 08bd4c
	uint32_t		 uncompressed_size;
Packit 08bd4c
	uint32_t		 offset;
Packit 08bd4c
	time_t			 mtime;
Packit 08bd4c
	uint16_t	 	 folder;
Packit 08bd4c
#define iFoldCONTINUED_FROM_PREV	0xFFFD
Packit 08bd4c
#define iFoldCONTINUED_TO_NEXT		0xFFFE
Packit 08bd4c
#define iFoldCONTINUED_PREV_AND_NEXT	0xFFFF
Packit 08bd4c
	unsigned char		 attr;
Packit 08bd4c
#define ATTR_RDONLY		0x01
Packit 08bd4c
#define ATTR_NAME_IS_UTF	0x80
Packit 08bd4c
	struct archive_string 	 pathname;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
struct cfheader {
Packit 08bd4c
	/* Total bytes of all file size in a Cabinet. */
Packit 08bd4c
	uint32_t		 total_bytes;
Packit 08bd4c
	uint32_t		 files_offset;
Packit 08bd4c
	uint16_t		 folder_count;
Packit 08bd4c
	uint16_t		 file_count;
Packit 08bd4c
	uint16_t		 flags;
Packit 08bd4c
#define PREV_CABINET	0x0001
Packit 08bd4c
#define NEXT_CABINET	0x0002
Packit 08bd4c
#define RESERVE_PRESENT	0x0004
Packit 08bd4c
	uint16_t		 setid;
Packit 08bd4c
	uint16_t		 cabinet;
Packit 08bd4c
	/* Version number. */
Packit 08bd4c
	unsigned char		 major;
Packit 08bd4c
	unsigned char		 minor;
Packit 08bd4c
	unsigned char		 cffolder;
Packit 08bd4c
	unsigned char		 cfdata;
Packit 08bd4c
	/* All folders in a cabinet. */
Packit 08bd4c
	struct cffolder		*folder_array;
Packit 08bd4c
	/* All files in a cabinet. */
Packit 08bd4c
	struct cffile		*file_array;
Packit 08bd4c
	int			 file_index;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
struct cab {
Packit 08bd4c
	/* entry_bytes_remaining is the number of bytes we expect.	    */
Packit 08bd4c
	int64_t			 entry_offset;
Packit 08bd4c
	int64_t			 entry_bytes_remaining;
Packit 08bd4c
	int64_t			 entry_unconsumed;
Packit 08bd4c
	int64_t			 entry_compressed_bytes_read;
Packit 08bd4c
	int64_t			 entry_uncompressed_bytes_read;
Packit 08bd4c
	struct cffolder		*entry_cffolder;
Packit 08bd4c
	struct cffile		*entry_cffile;
Packit 08bd4c
	struct cfdata		*entry_cfdata;
Packit 08bd4c
Packit 08bd4c
	/* Offset from beginning of a cabinet file. */
Packit 08bd4c
	int64_t			 cab_offset;
Packit 08bd4c
	struct cfheader		 cfheader;
Packit 08bd4c
	struct archive_wstring	 ws;
Packit 08bd4c
Packit 08bd4c
	/* Flag to mark progress that an archive was read their first header.*/
Packit 08bd4c
	char			 found_header;
Packit 08bd4c
	char			 end_of_archive;
Packit 08bd4c
	char			 end_of_entry;
Packit 08bd4c
	char			 end_of_entry_cleanup;
Packit 08bd4c
	char			 read_data_invoked;
Packit 08bd4c
	int64_t			 bytes_skipped;
Packit 08bd4c
Packit 08bd4c
	unsigned char		*uncompressed_buffer;
Packit 08bd4c
	size_t			 uncompressed_buffer_size;
Packit 08bd4c
Packit 08bd4c
	int			 init_default_conversion;
Packit 08bd4c
	struct archive_string_conv *sconv;
Packit 08bd4c
	struct archive_string_conv *sconv_default;
Packit 08bd4c
	struct archive_string_conv *sconv_utf8;
Packit 08bd4c
	char			 format_name[64];
Packit 08bd4c
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
	z_stream		 stream;
Packit 08bd4c
	char			 stream_valid;
Packit 08bd4c
#endif
Packit 08bd4c
	struct lzx_stream	 xstrm;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
static int	archive_read_format_cab_bid(struct archive_read *, int);
Packit 08bd4c
static int	archive_read_format_cab_options(struct archive_read *,
Packit 08bd4c
		    const char *, const char *);
Packit 08bd4c
static int	archive_read_format_cab_read_header(struct archive_read *,
Packit 08bd4c
		    struct archive_entry *);
Packit 08bd4c
static int	archive_read_format_cab_read_data(struct archive_read *,
Packit 08bd4c
		    const void **, size_t *, int64_t *);
Packit 08bd4c
static int	archive_read_format_cab_read_data_skip(struct archive_read *);
Packit 08bd4c
static int	archive_read_format_cab_cleanup(struct archive_read *);
Packit 08bd4c
Packit 08bd4c
static int	cab_skip_sfx(struct archive_read *);
Packit 08bd4c
static time_t	cab_dos_time(const unsigned char *);
Packit 08bd4c
static int	cab_read_data(struct archive_read *, const void **,
Packit 08bd4c
		    size_t *, int64_t *);
Packit 08bd4c
static int	cab_read_header(struct archive_read *);
Packit 08bd4c
static uint32_t cab_checksum_cfdata_4(const void *, size_t bytes, uint32_t);
Packit 08bd4c
static uint32_t cab_checksum_cfdata(const void *, size_t bytes, uint32_t);
Packit 08bd4c
static void	cab_checksum_update(struct archive_read *, size_t);
Packit 08bd4c
static int	cab_checksum_finish(struct archive_read *);
Packit 08bd4c
static int	cab_next_cfdata(struct archive_read *);
Packit 08bd4c
static const void *cab_read_ahead_cfdata(struct archive_read *, ssize_t *);
Packit 08bd4c
static const void *cab_read_ahead_cfdata_none(struct archive_read *, ssize_t *);
Packit 08bd4c
static const void *cab_read_ahead_cfdata_deflate(struct archive_read *,
Packit 08bd4c
		    ssize_t *);
Packit 08bd4c
static const void *cab_read_ahead_cfdata_lzx(struct archive_read *,
Packit 08bd4c
		    ssize_t *);
Packit 08bd4c
static int64_t	cab_consume_cfdata(struct archive_read *, int64_t);
Packit 08bd4c
static int64_t	cab_minimum_consume_cfdata(struct archive_read *, int64_t);
Packit 08bd4c
static int	lzx_decode_init(struct lzx_stream *, int);
Packit 08bd4c
static int	lzx_read_blocks(struct lzx_stream *, int);
Packit 08bd4c
static int	lzx_decode_blocks(struct lzx_stream *, int);
Packit 08bd4c
static void	lzx_decode_free(struct lzx_stream *);
Packit 08bd4c
static void	lzx_translation(struct lzx_stream *, void *, size_t, uint32_t);
Packit 08bd4c
static void	lzx_cleanup_bitstream(struct lzx_stream *);
Packit 08bd4c
static int	lzx_decode(struct lzx_stream *, int);
Packit 08bd4c
static int	lzx_read_pre_tree(struct lzx_stream *);
Packit 08bd4c
static int	lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);
Packit 08bd4c
static int	lzx_huffman_init(struct huffman *, size_t, int);
Packit 08bd4c
static void	lzx_huffman_free(struct huffman *);
Packit 08bd4c
static int	lzx_make_huffman_table(struct huffman *);
Packit 08bd4c
static inline int lzx_decode_huffman(struct huffman *, unsigned);
Packit 08bd4c
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
archive_read_support_format_cab(struct archive *_a)
Packit 08bd4c
{
Packit 08bd4c
	struct archive_read *a = (struct archive_read *)_a;
Packit 08bd4c
	struct cab *cab;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
Packit 08bd4c
	    ARCHIVE_STATE_NEW, "archive_read_support_format_cab");
Packit 08bd4c
Packit 08bd4c
	cab = (struct cab *)calloc(1, sizeof(*cab));
Packit 08bd4c
	if (cab == NULL) {
Packit 08bd4c
		archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
		    "Can't allocate CAB data");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	archive_string_init(&cab->ws);
Packit 08bd4c
	archive_wstring_ensure(&cab->ws, 256);
Packit 08bd4c
Packit 08bd4c
	r = __archive_read_register_format(a,
Packit 08bd4c
	    cab,
Packit 08bd4c
	    "cab",
Packit 08bd4c
	    archive_read_format_cab_bid,
Packit 08bd4c
	    archive_read_format_cab_options,
Packit 08bd4c
	    archive_read_format_cab_read_header,
Packit 08bd4c
	    archive_read_format_cab_read_data,
Packit 08bd4c
	    archive_read_format_cab_read_data_skip,
Packit 08bd4c
	    NULL,
Packit 08bd4c
	    archive_read_format_cab_cleanup,
Packit 08bd4c
	    NULL,
Packit 08bd4c
	    NULL);
Packit 08bd4c
Packit 08bd4c
	if (r != ARCHIVE_OK)
Packit 08bd4c
		free(cab);
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
find_cab_magic(const char *p)
Packit 08bd4c
{
Packit 08bd4c
	switch (p[4]) {
Packit 08bd4c
	case 0:
Packit 08bd4c
		/*
Packit 08bd4c
		 * Note: Self-Extraction program has 'MSCF' string in their
Packit 08bd4c
		 * program. If we were finding 'MSCF' string only, we got
Packit 08bd4c
		 * wrong place for Cabinet header, thus, we have to check
Packit 08bd4c
		 * following four bytes which are reserved and must be set
Packit 08bd4c
		 * to zero.
Packit 08bd4c
		 */
Packit 08bd4c
		if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)
Packit 08bd4c
			return 0;
Packit 08bd4c
		return 5;
Packit 08bd4c
	case 'F': return 1;
Packit 08bd4c
	case 'C': return 2;
Packit 08bd4c
	case 'S': return 3;
Packit 08bd4c
	case 'M': return 4;
Packit 08bd4c
	default:  return 5;
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_cab_bid(struct archive_read *a, int best_bid)
Packit 08bd4c
{
Packit 08bd4c
	const char *p;
Packit 08bd4c
	ssize_t bytes_avail, offset, window;
Packit 08bd4c
Packit 08bd4c
	/* If there's already a better bid than we can ever
Packit 08bd4c
	   make, don't bother testing. */
Packit 08bd4c
	if (best_bid > 64)
Packit 08bd4c
		return (-1);
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, 8, NULL)) == NULL)
Packit 08bd4c
		return (-1);
Packit 08bd4c
Packit 08bd4c
	if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)
Packit 08bd4c
		return (64);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Attempt to handle self-extracting archives
Packit 08bd4c
	 * by noting a PE header and searching forward
Packit 08bd4c
	 * up to 128k for a 'MSCF' marker.
Packit 08bd4c
	 */
Packit 08bd4c
	if (p[0] == 'M' && p[1] == 'Z') {
Packit 08bd4c
		offset = 0;
Packit 08bd4c
		window = 4096;
Packit 08bd4c
		while (offset < (1024 * 128)) {
Packit 08bd4c
			const char *h = __archive_read_ahead(a, offset + window,
Packit 08bd4c
			    &bytes_avail);
Packit 08bd4c
			if (h == NULL) {
Packit 08bd4c
				/* Remaining bytes are less than window. */
Packit 08bd4c
				window >>= 1;
Packit 08bd4c
				if (window < 128)
Packit 08bd4c
					return (0);
Packit 08bd4c
				continue;
Packit 08bd4c
			}
Packit 08bd4c
			p = h + offset;
Packit 08bd4c
			while (p + 8 < h + bytes_avail) {
Packit 08bd4c
				int next;
Packit 08bd4c
				if ((next = find_cab_magic(p)) == 0)
Packit 08bd4c
					return (64);
Packit 08bd4c
				p += next;
Packit 08bd4c
			}
Packit 08bd4c
			offset = p - h;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	return (0);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_cab_options(struct archive_read *a,
Packit 08bd4c
    const char *key, const char *val)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab;
Packit 08bd4c
	int ret = ARCHIVE_FAILED;
Packit 08bd4c
Packit 08bd4c
	cab = (struct cab *)(a->format->data);
Packit 08bd4c
	if (strcmp(key, "hdrcharset")  == 0) {
Packit 08bd4c
		if (val == NULL || val[0] == 0)
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "cab: hdrcharset option needs a character-set name");
Packit 08bd4c
		else {
Packit 08bd4c
			cab->sconv = archive_string_conversion_from_charset(
Packit 08bd4c
			    &a->archive, val, 0);
Packit 08bd4c
			if (cab->sconv != NULL)
Packit 08bd4c
				ret = ARCHIVE_OK;
Packit 08bd4c
			else
Packit 08bd4c
				ret = ARCHIVE_FATAL;
Packit 08bd4c
		}
Packit 08bd4c
		return (ret);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* Note: The "warn" return is just to inform the options
Packit 08bd4c
	 * supervisor that we didn't handle it.  It will generate
Packit 08bd4c
	 * a suitable error if no one used this option. */
Packit 08bd4c
	return (ARCHIVE_WARN);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
cab_skip_sfx(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	const char *p, *q;
Packit 08bd4c
	size_t skip;
Packit 08bd4c
	ssize_t bytes, window;
Packit 08bd4c
Packit 08bd4c
	window = 4096;
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		const char *h = __archive_read_ahead(a, window, &bytes);
Packit 08bd4c
		if (h == NULL) {
Packit 08bd4c
			/* Remaining size are less than window. */
Packit 08bd4c
			window >>= 1;
Packit 08bd4c
			if (window < 128) {
Packit 08bd4c
				archive_set_error(&a->archive,
Packit 08bd4c
				    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
				    "Couldn't find out CAB header");
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			}
Packit 08bd4c
			continue;
Packit 08bd4c
		}
Packit 08bd4c
		p = h;
Packit 08bd4c
		q = p + bytes;
Packit 08bd4c
Packit 08bd4c
		/*
Packit 08bd4c
		 * Scan ahead until we find something that looks
Packit 08bd4c
		 * like the cab header.
Packit 08bd4c
		 */
Packit 08bd4c
		while (p + 8 < q) {
Packit 08bd4c
			int next;
Packit 08bd4c
			if ((next = find_cab_magic(p)) == 0) {
Packit 08bd4c
				skip = p - h;
Packit 08bd4c
				__archive_read_consume(a, skip);
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			p += next;
Packit 08bd4c
		}
Packit 08bd4c
		skip = p - h;
Packit 08bd4c
		__archive_read_consume(a, skip);
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
truncated_error(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Truncated CAB header");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static ssize_t
Packit 08bd4c
cab_strnlen(const unsigned char *p, size_t maxlen)
Packit 08bd4c
{
Packit 08bd4c
	size_t i;
Packit 08bd4c
Packit 08bd4c
	for (i = 0; i <= maxlen; i++) {
Packit 08bd4c
		if (p[i] == 0)
Packit 08bd4c
			break;
Packit 08bd4c
	}
Packit 08bd4c
	if (i > maxlen)
Packit 08bd4c
		return (-1);/* invalid */
Packit 08bd4c
	return ((ssize_t)i);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* Read bytes as much as remaining. */
Packit 08bd4c
static const void *
Packit 08bd4c
cab_read_ahead_remaining(struct archive_read *a, size_t min, ssize_t *avail)
Packit 08bd4c
{
Packit 08bd4c
	const void *p;
Packit 08bd4c
Packit 08bd4c
	while (min > 0) {
Packit 08bd4c
		p = __archive_read_ahead(a, min, avail);
Packit 08bd4c
		if (p != NULL)
Packit 08bd4c
			return (p);
Packit 08bd4c
		min--;
Packit 08bd4c
	}
Packit 08bd4c
	return (NULL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* Convert a path separator '\' -> '/' */
Packit 08bd4c
static int
Packit 08bd4c
cab_convert_path_separator_1(struct archive_string *fn, unsigned char attr)
Packit 08bd4c
{
Packit 08bd4c
	size_t i;
Packit 08bd4c
	int mb;
Packit 08bd4c
Packit 08bd4c
	/* Easy check if we have '\' in multi-byte string. */
Packit 08bd4c
	mb = 0;
Packit 08bd4c
	for (i = 0; i < archive_strlen(fn); i++) {
Packit 08bd4c
		if (fn->s[i] == '\\') {
Packit 08bd4c
			if (mb) {
Packit 08bd4c
				/* This may be second byte of multi-byte
Packit 08bd4c
				 * character. */
Packit 08bd4c
				break;
Packit 08bd4c
			}
Packit 08bd4c
			fn->s[i] = '/';
Packit 08bd4c
			mb = 0;
Packit 08bd4c
		} else if ((fn->s[i] & 0x80) && !(attr & ATTR_NAME_IS_UTF))
Packit 08bd4c
			mb = 1;
Packit 08bd4c
		else
Packit 08bd4c
			mb = 0;
Packit 08bd4c
	}
Packit 08bd4c
	if (i == archive_strlen(fn))
Packit 08bd4c
		return (0);
Packit 08bd4c
	return (-1);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Replace a character '\' with '/' in wide character.
Packit 08bd4c
 */
Packit 08bd4c
static void
Packit 08bd4c
cab_convert_path_separator_2(struct cab *cab, struct archive_entry *entry)
Packit 08bd4c
{
Packit 08bd4c
	const wchar_t *wp;
Packit 08bd4c
	size_t i;
Packit 08bd4c
Packit 08bd4c
	/* If a conversion to wide character failed, force the replacement. */
Packit 08bd4c
	if ((wp = archive_entry_pathname_w(entry)) != NULL) {
Packit 08bd4c
		archive_wstrcpy(&(cab->ws), wp);
Packit 08bd4c
		for (i = 0; i < archive_strlen(&(cab->ws)); i++) {
Packit 08bd4c
			if (cab->ws.s[i] == L'\\')
Packit 08bd4c
				cab->ws.s[i] = L'/';
Packit 08bd4c
		}
Packit 08bd4c
		archive_entry_copy_pathname_w(entry, cab->ws.s);
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Read CFHEADER, CFFOLDER and CFFILE.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
cab_read_header(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	const unsigned char *p;
Packit 08bd4c
	struct cab *cab;
Packit 08bd4c
	struct cfheader *hd;
Packit 08bd4c
	size_t bytes, used;
Packit 08bd4c
	ssize_t len;
Packit 08bd4c
	int64_t skip;
Packit 08bd4c
	int err, i;
Packit 08bd4c
	int cur_folder, prev_folder;
Packit 08bd4c
	uint32_t offset32;
Packit 08bd4c
	
Packit 08bd4c
	a->archive.archive_format = ARCHIVE_FORMAT_CAB;
Packit 08bd4c
	if (a->archive.archive_format_name == NULL)
Packit 08bd4c
		a->archive.archive_format_name = "CAB";
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)
Packit 08bd4c
		return (truncated_error(a));
Packit 08bd4c
Packit 08bd4c
	cab = (struct cab *)(a->format->data);
Packit 08bd4c
	if (cab->found_header == 0 &&
Packit 08bd4c
	    p[0] == 'M' && p[1] == 'Z') {
Packit 08bd4c
		/* This is an executable?  Must be self-extracting... */
Packit 08bd4c
		err = cab_skip_sfx(a);
Packit 08bd4c
		if (err < ARCHIVE_WARN)
Packit 08bd4c
			return (err);
Packit 08bd4c
Packit 08bd4c
		/* Re-read header after processing the SFX. */
Packit 08bd4c
		if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	cab->cab_offset = 0;
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read CFHEADER.
Packit 08bd4c
	 */
Packit 08bd4c
	hd = &cab->cfheader;
Packit 08bd4c
	if (p[CFHEADER_signature+0] != 'M' || p[CFHEADER_signature+1] != 'S' ||
Packit 08bd4c
	    p[CFHEADER_signature+2] != 'C' || p[CFHEADER_signature+3] != 'F') {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Couldn't find out CAB header");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	hd->total_bytes = archive_le32dec(p + CFHEADER_cbCabinet);
Packit 08bd4c
	hd->files_offset = archive_le32dec(p + CFHEADER_coffFiles);
Packit 08bd4c
	hd->minor = p[CFHEADER_versionMinor];
Packit 08bd4c
	hd->major = p[CFHEADER_versionMajor];
Packit 08bd4c
	hd->folder_count = archive_le16dec(p + CFHEADER_cFolders);
Packit 08bd4c
	if (hd->folder_count == 0)
Packit 08bd4c
		goto invalid;
Packit 08bd4c
	hd->file_count = archive_le16dec(p + CFHEADER_cFiles);
Packit 08bd4c
	if (hd->file_count == 0)
Packit 08bd4c
		goto invalid;
Packit 08bd4c
	hd->flags = archive_le16dec(p + CFHEADER_flags);
Packit 08bd4c
	hd->setid = archive_le16dec(p + CFHEADER_setID);
Packit 08bd4c
	hd->cabinet = archive_le16dec(p + CFHEADER_iCabinet);
Packit 08bd4c
	used = CFHEADER_iCabinet + 2;
Packit 08bd4c
	if (hd->flags & RESERVE_PRESENT) {
Packit 08bd4c
		uint16_t cfheader;
Packit 08bd4c
		cfheader = archive_le16dec(p + CFHEADER_cbCFHeader);
Packit 08bd4c
		if (cfheader > 60000U)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
		hd->cffolder = p[CFHEADER_cbCFFolder];
Packit 08bd4c
		hd->cfdata = p[CFHEADER_cbCFData];
Packit 08bd4c
		used += 4;/* cbCFHeader, cbCFFolder and cbCFData */
Packit 08bd4c
		used += cfheader;/* abReserve */
Packit 08bd4c
	} else
Packit 08bd4c
		hd->cffolder = 0;/* Avoid compiling warning. */
Packit 08bd4c
	if (hd->flags & PREV_CABINET) {
Packit 08bd4c
		/* How many bytes are used for szCabinetPrev. */
Packit 08bd4c
		if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
		if ((len = cab_strnlen(p + used, 255)) <= 0)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
		used += len + 1;
Packit 08bd4c
		/* How many bytes are used for szDiskPrev. */
Packit 08bd4c
		if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
		if ((len = cab_strnlen(p + used, 255)) <= 0)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
		used += len + 1;
Packit 08bd4c
	}
Packit 08bd4c
	if (hd->flags & NEXT_CABINET) {
Packit 08bd4c
		/* How many bytes are used for szCabinetNext. */
Packit 08bd4c
		if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
		if ((len = cab_strnlen(p + used, 255)) <= 0)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
		used += len + 1;
Packit 08bd4c
		/* How many bytes are used for szDiskNext. */
Packit 08bd4c
		if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
		if ((len = cab_strnlen(p + used, 255)) <= 0)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
		used += len + 1;
Packit 08bd4c
	}
Packit 08bd4c
	__archive_read_consume(a, used);
Packit 08bd4c
	cab->cab_offset += used;
Packit 08bd4c
	used = 0;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read CFFOLDER.
Packit 08bd4c
	 */
Packit 08bd4c
	hd->folder_array = (struct cffolder *)calloc(
Packit 08bd4c
	    hd->folder_count, sizeof(struct cffolder));
Packit 08bd4c
	if (hd->folder_array == NULL)
Packit 08bd4c
		goto nomem;
Packit 08bd4c
	
Packit 08bd4c
	bytes = 8;
Packit 08bd4c
	if (hd->flags & RESERVE_PRESENT)
Packit 08bd4c
		bytes += hd->cffolder;
Packit 08bd4c
	bytes *= hd->folder_count;
Packit 08bd4c
	if ((p = __archive_read_ahead(a, bytes, NULL)) == NULL)
Packit 08bd4c
		return (truncated_error(a));
Packit 08bd4c
	offset32 = 0;
Packit 08bd4c
	for (i = 0; i < hd->folder_count; i++) {
Packit 08bd4c
		struct cffolder *folder = &(hd->folder_array[i]);
Packit 08bd4c
		folder->cfdata_offset_in_cab =
Packit 08bd4c
		    archive_le32dec(p + CFFOLDER_coffCabStart);
Packit 08bd4c
		folder->cfdata_count = archive_le16dec(p+CFFOLDER_cCFData);
Packit 08bd4c
		folder->comptype =
Packit 08bd4c
		    archive_le16dec(p+CFFOLDER_typeCompress) & 0x0F;
Packit 08bd4c
		folder->compdata =
Packit 08bd4c
		    archive_le16dec(p+CFFOLDER_typeCompress) >> 8;
Packit 08bd4c
		/* Get a compression name. */
Packit 08bd4c
		if (folder->comptype <
Packit 08bd4c
		    sizeof(compression_name) / sizeof(compression_name[0]))
Packit 08bd4c
			folder->compname = compression_name[folder->comptype];
Packit 08bd4c
		else
Packit 08bd4c
			folder->compname = "UNKNOWN";
Packit 08bd4c
		p += 8;
Packit 08bd4c
		used += 8;
Packit 08bd4c
		if (hd->flags & RESERVE_PRESENT) {
Packit 08bd4c
			p += hd->cffolder;/* abReserve */
Packit 08bd4c
			used += hd->cffolder;
Packit 08bd4c
		}
Packit 08bd4c
		/*
Packit 08bd4c
		 * Sanity check if each data is acceptable.
Packit 08bd4c
		 */
Packit 08bd4c
		if (offset32 >= folder->cfdata_offset_in_cab)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
		offset32 = folder->cfdata_offset_in_cab;
Packit 08bd4c
Packit 08bd4c
		/* Set a request to initialize zlib for the CFDATA of
Packit 08bd4c
		 * this folder. */
Packit 08bd4c
		folder->decompress_init = 0;
Packit 08bd4c
	}
Packit 08bd4c
	__archive_read_consume(a, used);
Packit 08bd4c
	cab->cab_offset += used;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read CFFILE.
Packit 08bd4c
	 */
Packit 08bd4c
	/* Seek read pointer to the offset of CFFILE if needed. */
Packit 08bd4c
	skip = (int64_t)hd->files_offset - cab->cab_offset;
Packit 08bd4c
	if (skip <  0) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
		    "Invalid offset of CFFILE %jd < %jd",
Packit 08bd4c
		    (intmax_t)hd->files_offset, (intmax_t)cab->cab_offset);
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	if (skip) {
Packit 08bd4c
		__archive_read_consume(a, skip);
Packit 08bd4c
		cab->cab_offset += skip;
Packit 08bd4c
	}
Packit 08bd4c
	/* Allocate memory for CFDATA */
Packit 08bd4c
	hd->file_array = (struct cffile *)calloc(
Packit 08bd4c
	    hd->file_count, sizeof(struct cffile));
Packit 08bd4c
	if (hd->file_array == NULL)
Packit 08bd4c
		goto nomem;
Packit 08bd4c
Packit 08bd4c
	prev_folder = -1;
Packit 08bd4c
	for (i = 0; i < hd->file_count; i++) {
Packit 08bd4c
		struct cffile *file = &(hd->file_array[i]);
Packit 08bd4c
		ssize_t avail;
Packit 08bd4c
Packit 08bd4c
		if ((p = __archive_read_ahead(a, 16, NULL)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
		file->uncompressed_size = archive_le32dec(p + CFFILE_cbFile);
Packit 08bd4c
		file->offset = archive_le32dec(p + CFFILE_uoffFolderStart);
Packit 08bd4c
		file->folder = archive_le16dec(p + CFFILE_iFolder);
Packit 08bd4c
		file->mtime = cab_dos_time(p + CFFILE_date_time);
Packit 08bd4c
		file->attr = (uint8_t)archive_le16dec(p + CFFILE_attribs);
Packit 08bd4c
		__archive_read_consume(a, 16);
Packit 08bd4c
Packit 08bd4c
		cab->cab_offset += 16;
Packit 08bd4c
		if ((p = cab_read_ahead_remaining(a, 256, &avail)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
		if ((len = cab_strnlen(p, avail-1)) <= 0)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
Packit 08bd4c
		/* Copy a pathname.  */
Packit 08bd4c
		archive_string_init(&(file->pathname));
Packit 08bd4c
		archive_strncpy(&(file->pathname), p, len);
Packit 08bd4c
		__archive_read_consume(a, len + 1);
Packit 08bd4c
		cab->cab_offset += len + 1;
Packit 08bd4c
Packit 08bd4c
		/*
Packit 08bd4c
		 * Sanity check if each data is acceptable.
Packit 08bd4c
		 */
Packit 08bd4c
		if (file->uncompressed_size > 0x7FFF8000)
Packit 08bd4c
			goto invalid;/* Too large */
Packit 08bd4c
		if ((int64_t)file->offset + (int64_t)file->uncompressed_size
Packit 08bd4c
		    > ARCHIVE_LITERAL_LL(0x7FFF8000))
Packit 08bd4c
			goto invalid;/* Too large */
Packit 08bd4c
		switch (file->folder) {
Packit 08bd4c
		case iFoldCONTINUED_TO_NEXT:
Packit 08bd4c
			/* This must be last file in a folder. */
Packit 08bd4c
			if (i != hd->file_count -1)
Packit 08bd4c
				goto invalid;
Packit 08bd4c
			cur_folder = hd->folder_count -1;
Packit 08bd4c
			break;
Packit 08bd4c
		case iFoldCONTINUED_PREV_AND_NEXT:
Packit 08bd4c
			/* This must be only one file in a folder. */
Packit 08bd4c
			if (hd->file_count != 1)
Packit 08bd4c
				goto invalid;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case iFoldCONTINUED_FROM_PREV:
Packit 08bd4c
			/* This must be first file in a folder. */
Packit 08bd4c
			if (i != 0)
Packit 08bd4c
				goto invalid;
Packit 08bd4c
			prev_folder = cur_folder = 0;
Packit 08bd4c
			offset32 = file->offset;
Packit 08bd4c
			break;
Packit 08bd4c
		default:
Packit 08bd4c
			if (file->folder >= hd->folder_count)
Packit 08bd4c
				goto invalid;
Packit 08bd4c
			cur_folder = file->folder;
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
		/* Dot not back track. */
Packit 08bd4c
		if (cur_folder < prev_folder)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
		if (cur_folder != prev_folder)
Packit 08bd4c
			offset32 = 0;
Packit 08bd4c
		prev_folder = cur_folder;
Packit 08bd4c
Packit 08bd4c
		/* Make sure there are not any blanks from last file
Packit 08bd4c
		 * contents. */
Packit 08bd4c
		if (offset32 != file->offset)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
		offset32 += file->uncompressed_size;
Packit 08bd4c
Packit 08bd4c
		/* CFDATA is available for file contents. */
Packit 08bd4c
		if (file->uncompressed_size > 0 &&
Packit 08bd4c
		    hd->folder_array[cur_folder].cfdata_count == 0)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (hd->cabinet != 0 || hd->flags & (PREV_CABINET | NEXT_CABINET)) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Multivolume cabinet file is unsupported");
Packit 08bd4c
		return (ARCHIVE_WARN);
Packit 08bd4c
	}
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
invalid:
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Invalid CAB header");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
nomem:
Packit 08bd4c
	archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
	    "Can't allocate memory for CAB data");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_cab_read_header(struct archive_read *a,
Packit 08bd4c
    struct archive_entry *entry)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab;
Packit 08bd4c
	struct cfheader *hd;
Packit 08bd4c
	struct cffolder *prev_folder;
Packit 08bd4c
	struct cffile *file;
Packit 08bd4c
	struct archive_string_conv *sconv;
Packit 08bd4c
	int err = ARCHIVE_OK, r;
Packit 08bd4c
	
Packit 08bd4c
	cab = (struct cab *)(a->format->data);
Packit 08bd4c
	if (cab->found_header == 0) {
Packit 08bd4c
		err = cab_read_header(a); 
Packit 08bd4c
		if (err < ARCHIVE_WARN)
Packit 08bd4c
			return (err);
Packit 08bd4c
		/* We've found the header. */
Packit 08bd4c
		cab->found_header = 1;
Packit 08bd4c
	}
Packit 08bd4c
	hd = &cab->cfheader;
Packit 08bd4c
Packit 08bd4c
	if (hd->file_index >= hd->file_count) {
Packit 08bd4c
		cab->end_of_archive = 1;
Packit 08bd4c
		return (ARCHIVE_EOF);
Packit 08bd4c
	}
Packit 08bd4c
	file = &hd->file_array[hd->file_index++];
Packit 08bd4c
Packit 08bd4c
	cab->end_of_entry = 0;
Packit 08bd4c
	cab->end_of_entry_cleanup = 0;
Packit 08bd4c
	cab->entry_compressed_bytes_read = 0;
Packit 08bd4c
	cab->entry_uncompressed_bytes_read = 0;
Packit 08bd4c
	cab->entry_unconsumed = 0;
Packit 08bd4c
	cab->entry_cffile = file;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Choose a proper folder.
Packit 08bd4c
	 */
Packit 08bd4c
	prev_folder = cab->entry_cffolder;
Packit 08bd4c
	switch (file->folder) {
Packit 08bd4c
	case iFoldCONTINUED_FROM_PREV:
Packit 08bd4c
	case iFoldCONTINUED_PREV_AND_NEXT:
Packit 08bd4c
		cab->entry_cffolder = &hd->folder_array[0];
Packit 08bd4c
		break;
Packit 08bd4c
	case iFoldCONTINUED_TO_NEXT:
Packit 08bd4c
		cab->entry_cffolder = &hd->folder_array[hd->folder_count-1];
Packit 08bd4c
		break;
Packit 08bd4c
	default:
Packit 08bd4c
		cab->entry_cffolder = &hd->folder_array[file->folder];
Packit 08bd4c
		break;
Packit 08bd4c
	}
Packit 08bd4c
	/* If a cffolder of this file is changed, reset a cfdata to read
Packit 08bd4c
	 * file contents from next cfdata. */
Packit 08bd4c
	if (prev_folder != cab->entry_cffolder)
Packit 08bd4c
		cab->entry_cfdata = NULL;
Packit 08bd4c
Packit 08bd4c
	/* If a pathname is UTF-8, prepare a string conversion object
Packit 08bd4c
	 * for UTF-8 and use it. */
Packit 08bd4c
	if (file->attr & ATTR_NAME_IS_UTF) {
Packit 08bd4c
		if (cab->sconv_utf8 == NULL) {
Packit 08bd4c
			cab->sconv_utf8 =
Packit 08bd4c
			    archive_string_conversion_from_charset(
Packit 08bd4c
				&(a->archive), "UTF-8", 1);
Packit 08bd4c
			if (cab->sconv_utf8 == NULL)
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
		sconv = cab->sconv_utf8;
Packit 08bd4c
	} else if (cab->sconv != NULL) {
Packit 08bd4c
		/* Choose the conversion specified by the option. */
Packit 08bd4c
		sconv = cab->sconv;
Packit 08bd4c
	} else {
Packit 08bd4c
		/* Choose the default conversion. */
Packit 08bd4c
		if (!cab->init_default_conversion) {
Packit 08bd4c
			cab->sconv_default =
Packit 08bd4c
			    archive_string_default_conversion_for_read(
Packit 08bd4c
			      &(a->archive));
Packit 08bd4c
			cab->init_default_conversion = 1;
Packit 08bd4c
		}
Packit 08bd4c
		sconv = cab->sconv_default;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Set a default value and common data
Packit 08bd4c
	 */
Packit 08bd4c
	r = cab_convert_path_separator_1(&(file->pathname), file->attr);
Packit 08bd4c
	if (archive_entry_copy_pathname_l(entry, file->pathname.s,
Packit 08bd4c
	    archive_strlen(&(file->pathname)), sconv) != 0) {
Packit 08bd4c
		if (errno == ENOMEM) {
Packit 08bd4c
			archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
			    "Can't allocate memory for Pathname");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
		archive_set_error(&a->archive,
Packit 08bd4c
		    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Pathname cannot be converted "
Packit 08bd4c
		    "from %s to current locale.",
Packit 08bd4c
		    archive_string_conversion_charset_name(sconv));
Packit 08bd4c
		err = ARCHIVE_WARN;
Packit 08bd4c
	}
Packit 08bd4c
	if (r < 0) {
Packit 08bd4c
		/* Convert a path separator '\' -> '/' */
Packit 08bd4c
		cab_convert_path_separator_2(cab, entry);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	archive_entry_set_size(entry, file->uncompressed_size);
Packit 08bd4c
	if (file->attr & ATTR_RDONLY)
Packit 08bd4c
		archive_entry_set_mode(entry, AE_IFREG | 0555);
Packit 08bd4c
	else
Packit 08bd4c
		archive_entry_set_mode(entry, AE_IFREG | 0666);
Packit 08bd4c
	archive_entry_set_mtime(entry, file->mtime, 0);
Packit 08bd4c
Packit 08bd4c
	cab->entry_bytes_remaining = file->uncompressed_size;
Packit 08bd4c
	cab->entry_offset = 0;
Packit 08bd4c
	/* We don't need compress data. */
Packit 08bd4c
	if (file->uncompressed_size == 0)
Packit 08bd4c
		cab->end_of_entry_cleanup = cab->end_of_entry = 1;
Packit 08bd4c
Packit 08bd4c
	/* Set up a more descriptive format name. */
Packit 08bd4c
	sprintf(cab->format_name, "CAB %d.%d (%s)",
Packit 08bd4c
	    hd->major, hd->minor, cab->entry_cffolder->compname);
Packit 08bd4c
	a->archive.archive_format_name = cab->format_name;
Packit 08bd4c
Packit 08bd4c
	return (err);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_cab_read_data(struct archive_read *a,
Packit 08bd4c
    const void **buff, size_t *size, int64_t *offset)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	switch (cab->entry_cffile->folder) {
Packit 08bd4c
	case iFoldCONTINUED_FROM_PREV:
Packit 08bd4c
	case iFoldCONTINUED_TO_NEXT:
Packit 08bd4c
	case iFoldCONTINUED_PREV_AND_NEXT:
Packit 08bd4c
		*buff = NULL;
Packit 08bd4c
		*size = 0;
Packit 08bd4c
		*offset = 0;
Packit 08bd4c
		archive_clear_error(&a->archive);
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Cannot restore this file split in multivolume.");
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
	default:
Packit 08bd4c
		break;
Packit 08bd4c
	}
Packit 08bd4c
	if (cab->read_data_invoked == 0) {
Packit 08bd4c
		if (cab->bytes_skipped) {
Packit 08bd4c
			if (cab->entry_cfdata == NULL) {
Packit 08bd4c
				r = cab_next_cfdata(a);
Packit 08bd4c
				if (r < 0)
Packit 08bd4c
					return (r);
Packit 08bd4c
			}
Packit 08bd4c
			if (cab_consume_cfdata(a, cab->bytes_skipped) < 0)
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			cab->bytes_skipped = 0;
Packit 08bd4c
		}
Packit 08bd4c
		cab->read_data_invoked = 1;
Packit 08bd4c
	}
Packit 08bd4c
	if (cab->entry_unconsumed) {
Packit 08bd4c
		/* Consume as much as the compressor actually used. */
Packit 08bd4c
		r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);
Packit 08bd4c
		cab->entry_unconsumed = 0;
Packit 08bd4c
		if (r < 0)
Packit 08bd4c
			return (r);
Packit 08bd4c
	}
Packit 08bd4c
	if (cab->end_of_archive || cab->end_of_entry) {
Packit 08bd4c
		if (!cab->end_of_entry_cleanup) {
Packit 08bd4c
			/* End-of-entry cleanup done. */
Packit 08bd4c
			cab->end_of_entry_cleanup = 1;
Packit 08bd4c
		}
Packit 08bd4c
		*offset = cab->entry_offset;
Packit 08bd4c
		*size = 0;
Packit 08bd4c
		*buff = NULL;
Packit 08bd4c
		return (ARCHIVE_EOF);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	return (cab_read_data(a, buff, size, offset));
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static uint32_t
Packit 08bd4c
cab_checksum_cfdata_4(const void *p, size_t bytes, uint32_t seed)
Packit 08bd4c
{
Packit 08bd4c
	const unsigned char *b;
Packit 08bd4c
	unsigned u32num;
Packit 08bd4c
	uint32_t sum;
Packit 08bd4c
Packit 08bd4c
	u32num = (unsigned)bytes / 4;
Packit 08bd4c
	sum = seed;
Packit 08bd4c
	b = p;
Packit 08bd4c
	for (;u32num > 0; --u32num) {
Packit 08bd4c
		sum ^= archive_le32dec(b);
Packit 08bd4c
		b += 4;
Packit 08bd4c
	}
Packit 08bd4c
	return (sum);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static uint32_t
Packit 08bd4c
cab_checksum_cfdata(const void *p, size_t bytes, uint32_t seed)
Packit 08bd4c
{
Packit 08bd4c
	const unsigned char *b;
Packit 08bd4c
	uint32_t sum;
Packit 08bd4c
	uint32_t t;
Packit 08bd4c
Packit 08bd4c
	sum = cab_checksum_cfdata_4(p, bytes, seed);
Packit 08bd4c
	b = p;
Packit 08bd4c
	b += bytes & ~3;
Packit 08bd4c
	t = 0;
Packit 08bd4c
	switch (bytes & 3) {
Packit 08bd4c
	case 3:
Packit 08bd4c
		t |= ((uint32_t)(*b++)) << 16;
Packit 08bd4c
		/* FALL THROUGH */
Packit 08bd4c
	case 2:
Packit 08bd4c
		t |= ((uint32_t)(*b++)) << 8;
Packit 08bd4c
		/* FALL THROUGH */
Packit 08bd4c
	case 1:
Packit 08bd4c
		t |= *b;
Packit 08bd4c
		/* FALL THROUGH */
Packit 08bd4c
	default:
Packit 08bd4c
		break;
Packit 08bd4c
	}
Packit 08bd4c
	sum ^= t;
Packit 08bd4c
Packit 08bd4c
	return (sum);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static void
Packit 08bd4c
cab_checksum_update(struct archive_read *a, size_t bytes)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	struct cfdata *cfdata = cab->entry_cfdata;
Packit 08bd4c
	const unsigned char *p;
Packit 08bd4c
	size_t sumbytes;
Packit 08bd4c
Packit 08bd4c
	if (cfdata->sum == 0 || cfdata->sum_ptr == NULL)
Packit 08bd4c
		return;
Packit 08bd4c
	/*
Packit 08bd4c
	 * Calculate the sum of this CFDATA.
Packit 08bd4c
	 * Make sure CFDATA must be calculated in four bytes.
Packit 08bd4c
	 */
Packit 08bd4c
	p = cfdata->sum_ptr;
Packit 08bd4c
	sumbytes = bytes;
Packit 08bd4c
	if (cfdata->sum_extra_avail) {
Packit 08bd4c
		while (cfdata->sum_extra_avail < 4 && sumbytes > 0) {
Packit 08bd4c
			cfdata->sum_extra[
Packit 08bd4c
			    cfdata->sum_extra_avail++] = *p++;
Packit 08bd4c
			sumbytes--;
Packit 08bd4c
		}
Packit 08bd4c
		if (cfdata->sum_extra_avail == 4) {
Packit 08bd4c
			cfdata->sum_calculated = cab_checksum_cfdata_4(
Packit 08bd4c
			    cfdata->sum_extra, 4, cfdata->sum_calculated);
Packit 08bd4c
			cfdata->sum_extra_avail = 0;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	if (sumbytes) {
Packit 08bd4c
		int odd = sumbytes & 3;
Packit 08bd4c
		if (sumbytes - odd > 0)
Packit 08bd4c
			cfdata->sum_calculated = cab_checksum_cfdata_4(
Packit 08bd4c
			    p, sumbytes - odd, cfdata->sum_calculated);
Packit 08bd4c
		if (odd)
Packit 08bd4c
			memcpy(cfdata->sum_extra, p + sumbytes - odd, odd);
Packit 08bd4c
		cfdata->sum_extra_avail = odd;
Packit 08bd4c
	}
Packit 08bd4c
	cfdata->sum_ptr = NULL;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
cab_checksum_finish(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	struct cfdata *cfdata = cab->entry_cfdata;
Packit 08bd4c
	int l;
Packit 08bd4c
Packit 08bd4c
	/* Do not need to compute a sum. */
Packit 08bd4c
	if (cfdata->sum == 0)
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Calculate the sum of remaining CFDATA.
Packit 08bd4c
	 */
Packit 08bd4c
	if (cfdata->sum_extra_avail) {
Packit 08bd4c
		cfdata->sum_calculated =
Packit 08bd4c
		    cab_checksum_cfdata(cfdata->sum_extra,
Packit 08bd4c
		       cfdata->sum_extra_avail, cfdata->sum_calculated);
Packit 08bd4c
		cfdata->sum_extra_avail = 0;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	l = 4;
Packit 08bd4c
	if (cab->cfheader.flags & RESERVE_PRESENT)
Packit 08bd4c
		l += cab->cfheader.cfdata;
Packit 08bd4c
	cfdata->sum_calculated = cab_checksum_cfdata(
Packit 08bd4c
	    cfdata->memimage + CFDATA_cbData, l, cfdata->sum_calculated);
Packit 08bd4c
	if (cfdata->sum_calculated != cfdata->sum) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Checksum error CFDATA[%d] %x:%x in %d bytes",
Packit 08bd4c
		    cab->entry_cffolder->cfdata_index -1,
Packit 08bd4c
		    cfdata->sum, cfdata->sum_calculated,
Packit 08bd4c
		    cfdata->compressed_size);
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
	}
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Read CFDATA if needed.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
cab_next_cfdata(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	struct cfdata *cfdata = cab->entry_cfdata;
Packit 08bd4c
Packit 08bd4c
	/* There are remaining bytes in current CFDATA, use it first. */
Packit 08bd4c
	if (cfdata != NULL && cfdata->uncompressed_bytes_remaining > 0)
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
Packit 08bd4c
	if (cfdata == NULL) {
Packit 08bd4c
		int64_t skip;
Packit 08bd4c
Packit 08bd4c
		cab->entry_cffolder->cfdata_index = 0;
Packit 08bd4c
Packit 08bd4c
		/* Seek read pointer to the offset of CFDATA if needed. */
Packit 08bd4c
		skip = cab->entry_cffolder->cfdata_offset_in_cab
Packit 08bd4c
			- cab->cab_offset;
Packit 08bd4c
		if (skip < 0) {
Packit 08bd4c
			int folder_index;
Packit 08bd4c
			switch (cab->entry_cffile->folder) {
Packit 08bd4c
			case iFoldCONTINUED_FROM_PREV:
Packit 08bd4c
			case iFoldCONTINUED_PREV_AND_NEXT:
Packit 08bd4c
				folder_index = 0;
Packit 08bd4c
				break;
Packit 08bd4c
			case iFoldCONTINUED_TO_NEXT:
Packit 08bd4c
				folder_index = cab->cfheader.folder_count-1;
Packit 08bd4c
				break;
Packit 08bd4c
			default:
Packit 08bd4c
				folder_index = cab->entry_cffile->folder;
Packit 08bd4c
				break;
Packit 08bd4c
			}
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "Invalid offset of CFDATA in folder(%d) %jd < %jd",
Packit 08bd4c
			    folder_index,
Packit 08bd4c
			    (intmax_t)cab->entry_cffolder->cfdata_offset_in_cab,
Packit 08bd4c
			    (intmax_t)cab->cab_offset);
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
		if (skip > 0) {
Packit 08bd4c
			if (__archive_read_consume(a, skip) < 0)
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			cab->cab_offset =
Packit 08bd4c
			    cab->entry_cffolder->cfdata_offset_in_cab;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Read a CFDATA.
Packit 08bd4c
	 */
Packit 08bd4c
	if (cab->entry_cffolder->cfdata_index <
Packit 08bd4c
	    cab->entry_cffolder->cfdata_count) {
Packit 08bd4c
		const unsigned char *p;
Packit 08bd4c
		int l;
Packit 08bd4c
Packit 08bd4c
		cfdata = &(cab->entry_cffolder->cfdata);
Packit 08bd4c
		cab->entry_cffolder->cfdata_index++;
Packit 08bd4c
		cab->entry_cfdata = cfdata;
Packit 08bd4c
		cfdata->sum_calculated = 0;
Packit 08bd4c
		cfdata->sum_extra_avail = 0;
Packit 08bd4c
		cfdata->sum_ptr = NULL;
Packit 08bd4c
		l = 8;
Packit 08bd4c
		if (cab->cfheader.flags & RESERVE_PRESENT)
Packit 08bd4c
			l += cab->cfheader.cfdata;
Packit 08bd4c
		if ((p = __archive_read_ahead(a, l, NULL)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
		cfdata->sum = archive_le32dec(p + CFDATA_csum);
Packit 08bd4c
		cfdata->compressed_size = archive_le16dec(p + CFDATA_cbData);
Packit 08bd4c
		cfdata->compressed_bytes_remaining = cfdata->compressed_size;
Packit 08bd4c
		cfdata->uncompressed_size =
Packit 08bd4c
		    archive_le16dec(p + CFDATA_cbUncomp);
Packit 08bd4c
		cfdata->uncompressed_bytes_remaining =
Packit 08bd4c
		    cfdata->uncompressed_size;
Packit 08bd4c
		cfdata->uncompressed_avail = 0;
Packit 08bd4c
		cfdata->read_offset = 0;
Packit 08bd4c
		cfdata->unconsumed = 0;
Packit 08bd4c
Packit 08bd4c
		/*
Packit 08bd4c
		 * Sanity check if data size is acceptable.
Packit 08bd4c
		 */
Packit 08bd4c
		if (cfdata->compressed_size == 0 ||
Packit 08bd4c
		    cfdata->compressed_size > (0x8000+6144))
Packit 08bd4c
			goto invalid;
Packit 08bd4c
		if (cfdata->uncompressed_size > 0x8000)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
		if (cfdata->uncompressed_size == 0) {
Packit 08bd4c
			switch (cab->entry_cffile->folder) {
Packit 08bd4c
			case iFoldCONTINUED_PREV_AND_NEXT:
Packit 08bd4c
			case iFoldCONTINUED_TO_NEXT:
Packit 08bd4c
				break;
Packit 08bd4c
			case iFoldCONTINUED_FROM_PREV:
Packit 08bd4c
			default:
Packit 08bd4c
				goto invalid;
Packit 08bd4c
			}
Packit 08bd4c
		}
Packit 08bd4c
		/* If CFDATA is not last in a folder, an uncompressed
Packit 08bd4c
		 * size must be 0x8000(32KBi) */
Packit 08bd4c
		if ((cab->entry_cffolder->cfdata_index <
Packit 08bd4c
		     cab->entry_cffolder->cfdata_count) &&
Packit 08bd4c
		       cfdata->uncompressed_size != 0x8000)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
Packit 08bd4c
		/* A compressed data size and an uncompressed data size must
Packit 08bd4c
		 * be the same in no compression mode. */
Packit 08bd4c
		if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&
Packit 08bd4c
		    cfdata->compressed_size != cfdata->uncompressed_size)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
Packit 08bd4c
		/*
Packit 08bd4c
		 * Save CFDATA image for sum check.
Packit 08bd4c
		 */
Packit 08bd4c
		if (cfdata->memimage_size < (size_t)l) {
Packit 08bd4c
			free(cfdata->memimage);
Packit 08bd4c
			cfdata->memimage = malloc(l);
Packit 08bd4c
			if (cfdata->memimage == NULL) {
Packit 08bd4c
				archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
				    "Can't allocate memory for CAB data");
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			}
Packit 08bd4c
			cfdata->memimage_size = l;
Packit 08bd4c
		}
Packit 08bd4c
		memcpy(cfdata->memimage, p, l);
Packit 08bd4c
Packit 08bd4c
		/* Consume bytes as much as we used. */
Packit 08bd4c
		__archive_read_consume(a, l);
Packit 08bd4c
		cab->cab_offset += l;
Packit 08bd4c
	} else if (cab->entry_cffolder->cfdata_count > 0) {
Packit 08bd4c
		/* Run out of all CFDATA in a folder. */
Packit 08bd4c
		cfdata->compressed_size = 0;
Packit 08bd4c
		cfdata->uncompressed_size = 0;
Packit 08bd4c
		cfdata->compressed_bytes_remaining = 0;
Packit 08bd4c
		cfdata->uncompressed_bytes_remaining = 0;
Packit 08bd4c
	} else {
Packit 08bd4c
		/* Current folder does not have any CFDATA. */
Packit 08bd4c
		cfdata = &(cab->entry_cffolder->cfdata);
Packit 08bd4c
		cab->entry_cfdata = cfdata;
Packit 08bd4c
		memset(cfdata, 0, sizeof(*cfdata));
Packit 08bd4c
	}
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
invalid:
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Invalid CFDATA");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Read ahead CFDATA.
Packit 08bd4c
 */
Packit 08bd4c
static const void *
Packit 08bd4c
cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	int err;
Packit 08bd4c
Packit 08bd4c
	err = cab_next_cfdata(a);
Packit 08bd4c
	if (err < ARCHIVE_OK) {
Packit 08bd4c
		*avail = err;
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	switch (cab->entry_cffolder->comptype) {
Packit 08bd4c
	case COMPTYPE_NONE:
Packit 08bd4c
		return (cab_read_ahead_cfdata_none(a, avail));
Packit 08bd4c
	case COMPTYPE_MSZIP:
Packit 08bd4c
		return (cab_read_ahead_cfdata_deflate(a, avail));
Packit 08bd4c
	case COMPTYPE_LZX:
Packit 08bd4c
		return (cab_read_ahead_cfdata_lzx(a, avail));
Packit 08bd4c
	default: /* Unsupported compression. */
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Unsupported CAB compression : %s",
Packit 08bd4c
		    cab->entry_cffolder->compname);
Packit 08bd4c
		*avail = ARCHIVE_FAILED;
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Read ahead CFDATA as uncompressed data.
Packit 08bd4c
 */
Packit 08bd4c
static const void *
Packit 08bd4c
cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	struct cfdata *cfdata;
Packit 08bd4c
	const void *d;
Packit 08bd4c
Packit 08bd4c
	cfdata = cab->entry_cfdata;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Note: '1' here is a performance optimization.
Packit 08bd4c
	 * Recall that the decompression layer returns a count of
Packit 08bd4c
	 * available bytes; asking for more than that forces the
Packit 08bd4c
	 * decompressor to combine reads by copying data.
Packit 08bd4c
	 */
Packit 08bd4c
	d = __archive_read_ahead(a, 1, avail);
Packit 08bd4c
	if (*avail <= 0) {
Packit 08bd4c
		*avail = truncated_error(a);
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	}
Packit 08bd4c
	if (*avail > cfdata->uncompressed_bytes_remaining)
Packit 08bd4c
		*avail = cfdata->uncompressed_bytes_remaining;
Packit 08bd4c
	cfdata->uncompressed_avail = cfdata->uncompressed_size;
Packit 08bd4c
	cfdata->unconsumed = *avail;
Packit 08bd4c
	cfdata->sum_ptr = d;
Packit 08bd4c
	return (d);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Read ahead CFDATA as deflate data.
Packit 08bd4c
 */
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
static const void *
Packit 08bd4c
cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	struct cfdata *cfdata;
Packit 08bd4c
	const void *d;
Packit 08bd4c
	int r, mszip;
Packit 08bd4c
	uint16_t uavail;
Packit 08bd4c
	char eod = 0;
Packit 08bd4c
Packit 08bd4c
	cfdata = cab->entry_cfdata;
Packit 08bd4c
	/* If the buffer hasn't been allocated, allocate it now. */
Packit 08bd4c
	if (cab->uncompressed_buffer == NULL) {
Packit 08bd4c
		cab->uncompressed_buffer_size = 0x8000;
Packit 08bd4c
		cab->uncompressed_buffer
Packit 08bd4c
		    = (unsigned char *)malloc(cab->uncompressed_buffer_size);
Packit 08bd4c
		if (cab->uncompressed_buffer == NULL) {
Packit 08bd4c
			archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
			    "No memory for CAB reader");
Packit 08bd4c
			*avail = ARCHIVE_FATAL;
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	uavail = cfdata->uncompressed_avail;
Packit 08bd4c
	if (uavail == cfdata->uncompressed_size) {
Packit 08bd4c
		d = cab->uncompressed_buffer + cfdata->read_offset;
Packit 08bd4c
		*avail = uavail - cfdata->read_offset;
Packit 08bd4c
		return (d);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (!cab->entry_cffolder->decompress_init) {
Packit 08bd4c
		cab->stream.next_in = NULL;
Packit 08bd4c
		cab->stream.avail_in = 0;
Packit 08bd4c
		cab->stream.total_in = 0;
Packit 08bd4c
		cab->stream.next_out = NULL;
Packit 08bd4c
		cab->stream.avail_out = 0;
Packit 08bd4c
		cab->stream.total_out = 0;
Packit 08bd4c
		if (cab->stream_valid)
Packit 08bd4c
			r = inflateReset(&cab->stream);
Packit 08bd4c
		else
Packit 08bd4c
			r = inflateInit2(&cab->stream,
Packit 08bd4c
			    -15 /* Don't check for zlib header */);
Packit 08bd4c
		if (r != Z_OK) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "Can't initialize deflate decompression.");
Packit 08bd4c
			*avail = ARCHIVE_FATAL;
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
		/* Stream structure has been set up. */
Packit 08bd4c
		cab->stream_valid = 1;
Packit 08bd4c
		/* We've initialized decompression for this stream. */
Packit 08bd4c
		cab->entry_cffolder->decompress_init = 1;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (cfdata->compressed_bytes_remaining == cfdata->compressed_size)
Packit 08bd4c
		mszip = 2;
Packit 08bd4c
	else
Packit 08bd4c
		mszip = 0;
Packit 08bd4c
	eod = 0;
Packit 08bd4c
	cab->stream.total_out = uavail;
Packit 08bd4c
	/*
Packit 08bd4c
	 * We always uncompress all data in current CFDATA.
Packit 08bd4c
	 */
Packit 08bd4c
	while (!eod && cab->stream.total_out < cfdata->uncompressed_size) {
Packit 08bd4c
		ssize_t bytes_avail;
Packit 08bd4c
Packit 08bd4c
		cab->stream.next_out =
Packit 08bd4c
		    cab->uncompressed_buffer + cab->stream.total_out;
Packit 08bd4c
		cab->stream.avail_out =
Packit 08bd4c
		    cfdata->uncompressed_size - cab->stream.total_out;
Packit 08bd4c
Packit 08bd4c
		d = __archive_read_ahead(a, 1, &bytes_avail);
Packit 08bd4c
		if (bytes_avail <= 0) {
Packit 08bd4c
			*avail = truncated_error(a);
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
		if (bytes_avail > cfdata->compressed_bytes_remaining)
Packit 08bd4c
			bytes_avail = cfdata->compressed_bytes_remaining;
Packit 08bd4c
		/*
Packit 08bd4c
		 * A bug in zlib.h: stream.next_in should be marked 'const'
Packit 08bd4c
		 * but isn't (the library never alters data through the
Packit 08bd4c
		 * next_in pointer, only reads it).  The result: this ugly
Packit 08bd4c
		 * cast to remove 'const'.
Packit 08bd4c
		 */
Packit 08bd4c
		cab->stream.next_in = (Bytef *)(uintptr_t)d;
Packit 08bd4c
		cab->stream.avail_in = (uInt)bytes_avail;
Packit 08bd4c
		cab->stream.total_in = 0;
Packit 08bd4c
Packit 08bd4c
		/* Cut out a tow-byte MSZIP signature(0x43, 0x4b). */
Packit 08bd4c
		if (mszip > 0) {
Packit 08bd4c
			if (bytes_avail <= 0)
Packit 08bd4c
				goto nomszip;
Packit 08bd4c
			if (bytes_avail <= mszip) {
Packit 08bd4c
				if (mszip == 2) {
Packit 08bd4c
					if (cab->stream.next_in[0] != 0x43)
Packit 08bd4c
						goto nomszip;
Packit 08bd4c
					if (bytes_avail > 1 &&
Packit 08bd4c
					    cab->stream.next_in[1] != 0x4b)
Packit 08bd4c
						goto nomszip;
Packit 08bd4c
				} else if (cab->stream.next_in[0] != 0x4b)
Packit 08bd4c
					goto nomszip;
Packit 08bd4c
				cfdata->unconsumed = bytes_avail;
Packit 08bd4c
				cfdata->sum_ptr = d;
Packit 08bd4c
				if (cab_minimum_consume_cfdata(
Packit 08bd4c
				    a, cfdata->unconsumed) < 0) {
Packit 08bd4c
					*avail = ARCHIVE_FATAL;
Packit 08bd4c
					return (NULL);
Packit 08bd4c
				}
Packit 08bd4c
				mszip -= (int)bytes_avail;
Packit 08bd4c
				continue;
Packit 08bd4c
			}
Packit 08bd4c
			if (mszip == 1 && cab->stream.next_in[0] != 0x4b)
Packit 08bd4c
				goto nomszip;
Packit 08bd4c
			else if (cab->stream.next_in[0] != 0x43 ||
Packit 08bd4c
			    cab->stream.next_in[1] != 0x4b)
Packit 08bd4c
				goto nomszip;
Packit 08bd4c
			cab->stream.next_in += mszip;
Packit 08bd4c
			cab->stream.avail_in -= mszip;
Packit 08bd4c
			cab->stream.total_in += mszip;
Packit 08bd4c
			mszip = 0;
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		r = inflate(&cab->stream, 0);
Packit 08bd4c
		switch (r) {
Packit 08bd4c
		case Z_OK:
Packit 08bd4c
			break;
Packit 08bd4c
		case Z_STREAM_END:
Packit 08bd4c
			eod = 1;
Packit 08bd4c
			break;
Packit 08bd4c
		default:
Packit 08bd4c
			goto zlibfailed;
Packit 08bd4c
		}
Packit 08bd4c
		cfdata->unconsumed = cab->stream.total_in;
Packit 08bd4c
		cfdata->sum_ptr = d;
Packit 08bd4c
		if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
Packit 08bd4c
			*avail = ARCHIVE_FATAL;
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	uavail = (uint16_t)cab->stream.total_out;
Packit 08bd4c
Packit 08bd4c
	if (uavail < cfdata->uncompressed_size) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
		    "Invalid uncompressed size (%d < %d)",
Packit 08bd4c
		    uavail, cfdata->uncompressed_size);
Packit 08bd4c
		*avail = ARCHIVE_FATAL;
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Note: I suspect there is a bug in makecab.exe because, in rare
Packit 08bd4c
	 * case, compressed bytes are still remaining regardless we have
Packit 08bd4c
	 * gotten all uncompressed bytes, which size is recorded in CFDATA,
Packit 08bd4c
	 * as much as we need, and we have to use the garbage so as to
Packit 08bd4c
	 * correctly compute the sum of CFDATA accordingly.
Packit 08bd4c
	 */
Packit 08bd4c
	if (cfdata->compressed_bytes_remaining > 0) {
Packit 08bd4c
		ssize_t bytes_avail;
Packit 08bd4c
Packit 08bd4c
		d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
Packit 08bd4c
		    &bytes_avail);
Packit 08bd4c
		if (bytes_avail <= 0) {
Packit 08bd4c
			*avail = truncated_error(a);
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
		cfdata->unconsumed = cfdata->compressed_bytes_remaining;
Packit 08bd4c
		cfdata->sum_ptr = d;
Packit 08bd4c
		if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
Packit 08bd4c
			*avail = ARCHIVE_FATAL;
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Set dictionary data for decompressing of next CFDATA, which
Packit 08bd4c
	 * in the same folder. This is why we always do decompress CFDATA
Packit 08bd4c
	 * even if beginning CFDATA or some of CFDATA are not used in
Packit 08bd4c
	 * skipping file data.
Packit 08bd4c
	 */
Packit 08bd4c
	if (cab->entry_cffolder->cfdata_index <
Packit 08bd4c
	    cab->entry_cffolder->cfdata_count) {
Packit 08bd4c
		r = inflateReset(&cab->stream);
Packit 08bd4c
		if (r != Z_OK)
Packit 08bd4c
			goto zlibfailed;
Packit 08bd4c
		r = inflateSetDictionary(&cab->stream,
Packit 08bd4c
		    cab->uncompressed_buffer, cfdata->uncompressed_size);
Packit 08bd4c
		if (r != Z_OK)
Packit 08bd4c
			goto zlibfailed;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	d = cab->uncompressed_buffer + cfdata->read_offset;
Packit 08bd4c
	*avail = uavail - cfdata->read_offset;
Packit 08bd4c
	cfdata->uncompressed_avail = uavail;
Packit 08bd4c
Packit 08bd4c
	return (d);
Packit 08bd4c
Packit 08bd4c
zlibfailed:
Packit 08bd4c
	switch (r) {
Packit 08bd4c
	case Z_MEM_ERROR:
Packit 08bd4c
		archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
		    "Out of memory for deflate decompression");
Packit 08bd4c
		break;
Packit 08bd4c
	default:
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
		    "Deflate decompression failed (%d)", r);
Packit 08bd4c
		break;
Packit 08bd4c
	}
Packit 08bd4c
	*avail = ARCHIVE_FATAL;
Packit 08bd4c
	return (NULL);
Packit 08bd4c
nomszip:
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
	    "CFDATA incorrect(no MSZIP signature)");
Packit 08bd4c
	*avail = ARCHIVE_FATAL;
Packit 08bd4c
	return (NULL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
#else /* HAVE_ZLIB_H */
Packit 08bd4c
Packit 08bd4c
static const void *
Packit 08bd4c
cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
Packit 08bd4c
{
Packit 08bd4c
	*avail = ARCHIVE_FATAL;
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
	    "libarchive compiled without deflate support (no libz)");
Packit 08bd4c
	return (NULL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
#endif /* HAVE_ZLIB_H */
Packit 08bd4c
Packit 08bd4c
static const void *
Packit 08bd4c
cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	struct cfdata *cfdata;
Packit 08bd4c
	const void *d;
Packit 08bd4c
	int r;
Packit 08bd4c
	uint16_t uavail;
Packit 08bd4c
Packit 08bd4c
	cfdata = cab->entry_cfdata;
Packit 08bd4c
	/* If the buffer hasn't been allocated, allocate it now. */
Packit 08bd4c
	if (cab->uncompressed_buffer == NULL) {
Packit 08bd4c
		cab->uncompressed_buffer_size = 0x8000;
Packit 08bd4c
		cab->uncompressed_buffer
Packit 08bd4c
		    = (unsigned char *)malloc(cab->uncompressed_buffer_size);
Packit 08bd4c
		if (cab->uncompressed_buffer == NULL) {
Packit 08bd4c
			archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
			    "No memory for CAB reader");
Packit 08bd4c
			*avail = ARCHIVE_FATAL;
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	uavail = cfdata->uncompressed_avail;
Packit 08bd4c
	if (uavail == cfdata->uncompressed_size) {
Packit 08bd4c
		d = cab->uncompressed_buffer + cfdata->read_offset;
Packit 08bd4c
		*avail = uavail - cfdata->read_offset;
Packit 08bd4c
		return (d);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (!cab->entry_cffolder->decompress_init) {
Packit 08bd4c
		r = lzx_decode_init(&cab->xstrm,
Packit 08bd4c
		    cab->entry_cffolder->compdata);
Packit 08bd4c
		if (r != ARCHIVE_OK) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "Can't initialize LZX decompression.");
Packit 08bd4c
			*avail = ARCHIVE_FATAL;
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
		/* We've initialized decompression for this stream. */
Packit 08bd4c
		cab->entry_cffolder->decompress_init = 1;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* Clean up remaining bits of previous CFDATA. */
Packit 08bd4c
	lzx_cleanup_bitstream(&cab->xstrm);
Packit 08bd4c
	cab->xstrm.total_out = uavail;
Packit 08bd4c
	while (cab->xstrm.total_out < cfdata->uncompressed_size) {
Packit 08bd4c
		ssize_t bytes_avail;
Packit 08bd4c
Packit 08bd4c
		cab->xstrm.next_out =
Packit 08bd4c
		    cab->uncompressed_buffer + cab->xstrm.total_out;
Packit 08bd4c
		cab->xstrm.avail_out =
Packit 08bd4c
		    cfdata->uncompressed_size - cab->xstrm.total_out;
Packit 08bd4c
Packit 08bd4c
		d = __archive_read_ahead(a, 1, &bytes_avail);
Packit 08bd4c
		if (bytes_avail <= 0) {
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Truncated CAB file data");
Packit 08bd4c
			*avail = ARCHIVE_FATAL;
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
		if (bytes_avail > cfdata->compressed_bytes_remaining)
Packit 08bd4c
			bytes_avail = cfdata->compressed_bytes_remaining;
Packit 08bd4c
Packit 08bd4c
		cab->xstrm.next_in = d;
Packit 08bd4c
		cab->xstrm.avail_in = bytes_avail;
Packit 08bd4c
		cab->xstrm.total_in = 0;
Packit 08bd4c
		r = lzx_decode(&cab->xstrm,
Packit 08bd4c
		    cfdata->compressed_bytes_remaining == bytes_avail);
Packit 08bd4c
		switch (r) {
Packit 08bd4c
		case ARCHIVE_OK:
Packit 08bd4c
		case ARCHIVE_EOF:
Packit 08bd4c
			break;
Packit 08bd4c
		default:
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "LZX decompression failed (%d)", r);
Packit 08bd4c
			*avail = ARCHIVE_FATAL;
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
		cfdata->unconsumed = cab->xstrm.total_in;
Packit 08bd4c
		cfdata->sum_ptr = d;
Packit 08bd4c
		if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
Packit 08bd4c
			*avail = ARCHIVE_FATAL;
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	uavail = (uint16_t)cab->xstrm.total_out;
Packit 08bd4c
	/*
Packit 08bd4c
	 * Make sure a read pointer advances to next CFDATA.
Packit 08bd4c
	 */
Packit 08bd4c
	if (cfdata->compressed_bytes_remaining > 0) {
Packit 08bd4c
		ssize_t bytes_avail;
Packit 08bd4c
Packit 08bd4c
		d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
Packit 08bd4c
		    &bytes_avail);
Packit 08bd4c
		if (bytes_avail <= 0) {
Packit 08bd4c
			*avail = truncated_error(a);
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
		cfdata->unconsumed = cfdata->compressed_bytes_remaining;
Packit 08bd4c
		cfdata->sum_ptr = d;
Packit 08bd4c
		if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
Packit 08bd4c
			*avail = ARCHIVE_FATAL;
Packit 08bd4c
			return (NULL);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Translation reversal of x86 processor CALL byte sequence(E8).
Packit 08bd4c
	 */
Packit 08bd4c
	lzx_translation(&cab->xstrm, cab->uncompressed_buffer,
Packit 08bd4c
	    cfdata->uncompressed_size,
Packit 08bd4c
	    (cab->entry_cffolder->cfdata_index-1) * 0x8000);
Packit 08bd4c
Packit 08bd4c
	d = cab->uncompressed_buffer + cfdata->read_offset;
Packit 08bd4c
	*avail = uavail - cfdata->read_offset;
Packit 08bd4c
	cfdata->uncompressed_avail = uavail;
Packit 08bd4c
Packit 08bd4c
	return (d);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Consume CFDATA.
Packit 08bd4c
 * We always decompress CFDATA to consume CFDATA as much as we need
Packit 08bd4c
 * in uncompressed bytes because all CFDATA in a folder are related
Packit 08bd4c
 * so we do not skip any CFDATA without decompressing.
Packit 08bd4c
 * Note: If the folder of a CFFILE is iFoldCONTINUED_PREV_AND_NEXT or
Packit 08bd4c
 * iFoldCONTINUED_FROM_PREV, we won't decompress because a CFDATA for
Packit 08bd4c
 * the CFFILE is remaining bytes of previous Multivolume CAB file.
Packit 08bd4c
 */
Packit 08bd4c
static int64_t
Packit 08bd4c
cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	struct cfdata *cfdata;
Packit 08bd4c
	int64_t cbytes, rbytes;
Packit 08bd4c
	int err;
Packit 08bd4c
Packit 08bd4c
	rbytes = cab_minimum_consume_cfdata(a, consumed_bytes);
Packit 08bd4c
	if (rbytes < 0)
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
Packit 08bd4c
	cfdata = cab->entry_cfdata;
Packit 08bd4c
	while (rbytes > 0) {
Packit 08bd4c
		ssize_t avail;
Packit 08bd4c
Packit 08bd4c
		if (cfdata->compressed_size == 0) {
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Invalid CFDATA");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
		cbytes = cfdata->uncompressed_bytes_remaining;
Packit 08bd4c
		if (cbytes > rbytes)
Packit 08bd4c
			cbytes = rbytes;
Packit 08bd4c
		rbytes -= cbytes;
Packit 08bd4c
Packit 08bd4c
		if (cfdata->uncompressed_avail == 0 &&
Packit 08bd4c
		   (cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT ||
Packit 08bd4c
		    cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) {
Packit 08bd4c
			/* We have not read any data yet. */
Packit 08bd4c
			if (cbytes == cfdata->uncompressed_bytes_remaining) {
Packit 08bd4c
				/* Skip whole current CFDATA. */
Packit 08bd4c
				__archive_read_consume(a,
Packit 08bd4c
				    cfdata->compressed_size);
Packit 08bd4c
				cab->cab_offset += cfdata->compressed_size;
Packit 08bd4c
				cfdata->compressed_bytes_remaining = 0;
Packit 08bd4c
				cfdata->uncompressed_bytes_remaining = 0;
Packit 08bd4c
				err = cab_next_cfdata(a);
Packit 08bd4c
				if (err < 0)
Packit 08bd4c
					return (err);
Packit 08bd4c
				cfdata = cab->entry_cfdata;
Packit 08bd4c
				if (cfdata->uncompressed_size == 0) {
Packit 08bd4c
					switch (cab->entry_cffile->folder) {
Packit 08bd4c
					case iFoldCONTINUED_PREV_AND_NEXT:
Packit 08bd4c
					case iFoldCONTINUED_TO_NEXT:
Packit 08bd4c
					case iFoldCONTINUED_FROM_PREV:
Packit 08bd4c
						rbytes = 0;
Packit 08bd4c
						break;
Packit 08bd4c
					default:
Packit 08bd4c
						break;
Packit 08bd4c
					}
Packit 08bd4c
				}
Packit 08bd4c
				continue;
Packit 08bd4c
			}
Packit 08bd4c
			cfdata->read_offset += (uint16_t)cbytes;
Packit 08bd4c
			cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
Packit 08bd4c
			break;
Packit 08bd4c
		} else if (cbytes == 0) {
Packit 08bd4c
			err = cab_next_cfdata(a);
Packit 08bd4c
			if (err < 0)
Packit 08bd4c
				return (err);
Packit 08bd4c
			cfdata = cab->entry_cfdata;
Packit 08bd4c
			if (cfdata->uncompressed_size == 0) {
Packit 08bd4c
				switch (cab->entry_cffile->folder) {
Packit 08bd4c
				case iFoldCONTINUED_PREV_AND_NEXT:
Packit 08bd4c
				case iFoldCONTINUED_TO_NEXT:
Packit 08bd4c
				case iFoldCONTINUED_FROM_PREV:
Packit 08bd4c
					return (ARCHIVE_FATAL);
Packit 08bd4c
				default:
Packit 08bd4c
					break;
Packit 08bd4c
				}
Packit 08bd4c
			}
Packit 08bd4c
			continue;
Packit 08bd4c
		}
Packit 08bd4c
		while (cbytes > 0) {
Packit 08bd4c
			(void)cab_read_ahead_cfdata(a, &avail);
Packit 08bd4c
			if (avail <= 0)
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			if (avail > cbytes)
Packit 08bd4c
				avail = (ssize_t)cbytes;
Packit 08bd4c
			if (cab_minimum_consume_cfdata(a, avail) < 0)
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			cbytes -= avail;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	return (consumed_bytes);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Consume CFDATA as much as we have already gotten and
Packit 08bd4c
 * compute the sum of CFDATA.
Packit 08bd4c
 */
Packit 08bd4c
static int64_t
Packit 08bd4c
cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	struct cfdata *cfdata;
Packit 08bd4c
	int64_t cbytes, rbytes;
Packit 08bd4c
	int err;
Packit 08bd4c
Packit 08bd4c
	cfdata = cab->entry_cfdata;
Packit 08bd4c
	rbytes = consumed_bytes;
Packit 08bd4c
	if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {
Packit 08bd4c
		if (consumed_bytes < cfdata->unconsumed)
Packit 08bd4c
			cbytes = consumed_bytes;
Packit 08bd4c
		else
Packit 08bd4c
			cbytes = cfdata->unconsumed;
Packit 08bd4c
		rbytes -= cbytes; 
Packit 08bd4c
		cfdata->read_offset += (uint16_t)cbytes;
Packit 08bd4c
		cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
Packit 08bd4c
		cfdata->unconsumed -= cbytes;
Packit 08bd4c
	} else {
Packit 08bd4c
		cbytes = cfdata->uncompressed_avail - cfdata->read_offset;
Packit 08bd4c
		if (cbytes > 0) {
Packit 08bd4c
			if (consumed_bytes < cbytes)
Packit 08bd4c
				cbytes = consumed_bytes;
Packit 08bd4c
			rbytes -= cbytes;
Packit 08bd4c
			cfdata->read_offset += (uint16_t)cbytes;
Packit 08bd4c
			cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		if (cfdata->unconsumed) {
Packit 08bd4c
			cbytes = cfdata->unconsumed;
Packit 08bd4c
			cfdata->unconsumed = 0;
Packit 08bd4c
		} else
Packit 08bd4c
			cbytes = 0;
Packit 08bd4c
	}
Packit 08bd4c
	if (cbytes) {
Packit 08bd4c
		/* Compute the sum. */
Packit 08bd4c
		cab_checksum_update(a, (size_t)cbytes);
Packit 08bd4c
Packit 08bd4c
		/* Consume as much as the compressor actually used. */
Packit 08bd4c
		__archive_read_consume(a, cbytes);
Packit 08bd4c
		cab->cab_offset += cbytes;
Packit 08bd4c
		cfdata->compressed_bytes_remaining -= (uint16_t)cbytes;
Packit 08bd4c
		if (cfdata->compressed_bytes_remaining == 0) {
Packit 08bd4c
			err = cab_checksum_finish(a);
Packit 08bd4c
			if (err < 0)
Packit 08bd4c
				return (err);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	return (rbytes);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
Packit 08bd4c
 * cab->end_of_entry if it consumes all of the data.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
cab_read_data(struct archive_read *a, const void **buff,
Packit 08bd4c
    size_t *size, int64_t *offset)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	ssize_t bytes_avail;
Packit 08bd4c
Packit 08bd4c
	if (cab->entry_bytes_remaining == 0) {
Packit 08bd4c
		*buff = NULL;
Packit 08bd4c
		*size = 0;
Packit 08bd4c
		*offset = cab->entry_offset;
Packit 08bd4c
		cab->end_of_entry = 1;
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	*buff = cab_read_ahead_cfdata(a, &bytes_avail);
Packit 08bd4c
	if (bytes_avail <= 0) {
Packit 08bd4c
		*buff = NULL;
Packit 08bd4c
		*size = 0;
Packit 08bd4c
		*offset = 0;
Packit 08bd4c
		if (bytes_avail == 0 &&
Packit 08bd4c
		    cab->entry_cfdata->uncompressed_size == 0) {
Packit 08bd4c
			/* All of CFDATA in a folder has been handled. */
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT, "Invalid CFDATA");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		} else
Packit 08bd4c
			return ((int)bytes_avail);
Packit 08bd4c
	}
Packit 08bd4c
	if (bytes_avail > cab->entry_bytes_remaining)
Packit 08bd4c
		bytes_avail = (ssize_t)cab->entry_bytes_remaining;
Packit 08bd4c
Packit 08bd4c
	*size = bytes_avail;
Packit 08bd4c
	*offset = cab->entry_offset;
Packit 08bd4c
	cab->entry_offset += bytes_avail;
Packit 08bd4c
	cab->entry_bytes_remaining -= bytes_avail;
Packit 08bd4c
	if (cab->entry_bytes_remaining == 0)
Packit 08bd4c
		cab->end_of_entry = 1;
Packit 08bd4c
	cab->entry_unconsumed = bytes_avail;
Packit 08bd4c
	if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {
Packit 08bd4c
		/* Don't consume more than current entry used. */
Packit 08bd4c
		if (cab->entry_cfdata->unconsumed > cab->entry_unconsumed)
Packit 08bd4c
			cab->entry_cfdata->unconsumed = cab->entry_unconsumed;
Packit 08bd4c
	}
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_cab_read_data_skip(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab;
Packit 08bd4c
	int64_t bytes_skipped;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	cab = (struct cab *)(a->format->data);
Packit 08bd4c
Packit 08bd4c
	if (cab->end_of_archive)
Packit 08bd4c
		return (ARCHIVE_EOF);
Packit 08bd4c
Packit 08bd4c
	if (!cab->read_data_invoked) {
Packit 08bd4c
		cab->bytes_skipped += cab->entry_bytes_remaining;
Packit 08bd4c
		cab->entry_bytes_remaining = 0;
Packit 08bd4c
		/* This entry is finished and done. */
Packit 08bd4c
		cab->end_of_entry_cleanup = cab->end_of_entry = 1;
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (cab->entry_unconsumed) {
Packit 08bd4c
		/* Consume as much as the compressor actually used. */
Packit 08bd4c
		r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);
Packit 08bd4c
		cab->entry_unconsumed = 0;
Packit 08bd4c
		if (r < 0)
Packit 08bd4c
			return (r);
Packit 08bd4c
	} else if (cab->entry_cfdata == NULL) {
Packit 08bd4c
		r = cab_next_cfdata(a);
Packit 08bd4c
		if (r < 0)
Packit 08bd4c
			return (r);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* if we've already read to end of data, we're done. */
Packit 08bd4c
	if (cab->end_of_entry_cleanup)
Packit 08bd4c
		return (ARCHIVE_OK);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * If the length is at the beginning, we can skip the
Packit 08bd4c
	 * compressed data much more quickly.
Packit 08bd4c
	 */
Packit 08bd4c
	bytes_skipped = cab_consume_cfdata(a, cab->entry_bytes_remaining);
Packit 08bd4c
	if (bytes_skipped < 0)
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
Packit 08bd4c
	/* If the compression type is none(uncompressed), we've already
Packit 08bd4c
	 * consumed data as much as the current entry size. */
Packit 08bd4c
	if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&
Packit 08bd4c
	    cab->entry_cfdata != NULL)
Packit 08bd4c
		cab->entry_cfdata->unconsumed = 0;
Packit 08bd4c
Packit 08bd4c
	/* This entry is finished and done. */
Packit 08bd4c
	cab->end_of_entry_cleanup = cab->end_of_entry = 1;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_cab_cleanup(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct cab *cab = (struct cab *)(a->format->data);
Packit 08bd4c
	struct cfheader *hd = &cab->cfheader;
Packit 08bd4c
	int i;
Packit 08bd4c
Packit 08bd4c
	if (hd->folder_array != NULL) {
Packit 08bd4c
		for (i = 0; i < hd->folder_count; i++)
Packit 08bd4c
			free(hd->folder_array[i].cfdata.memimage);
Packit 08bd4c
		free(hd->folder_array);
Packit 08bd4c
	}
Packit 08bd4c
	if (hd->file_array != NULL) {
Packit 08bd4c
		for (i = 0; i < cab->cfheader.file_count; i++)
Packit 08bd4c
			archive_string_free(&(hd->file_array[i].pathname));
Packit 08bd4c
		free(hd->file_array);
Packit 08bd4c
	}
Packit 08bd4c
#ifdef HAVE_ZLIB_H
Packit 08bd4c
	if (cab->stream_valid)
Packit 08bd4c
		inflateEnd(&cab->stream);
Packit 08bd4c
#endif
Packit 08bd4c
	lzx_decode_free(&cab->xstrm);
Packit 08bd4c
	archive_wstring_free(&cab->ws);
Packit 08bd4c
	free(cab->uncompressed_buffer);
Packit 08bd4c
	free(cab);
Packit 08bd4c
	(a->format->data) = NULL;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* Convert an MSDOS-style date/time into Unix-style time. */
Packit 08bd4c
static time_t
Packit 08bd4c
cab_dos_time(const unsigned char *p)
Packit 08bd4c
{
Packit 08bd4c
	int msTime, msDate;
Packit 08bd4c
	struct tm ts;
Packit 08bd4c
Packit 08bd4c
	msDate = archive_le16dec(p);
Packit 08bd4c
	msTime = archive_le16dec(p+2);
Packit 08bd4c
Packit 08bd4c
	memset(&ts, 0, sizeof(ts));
Packit 08bd4c
	ts.tm_year = ((msDate >> 9) & 0x7f) + 80;   /* Years since 1900. */
Packit 08bd4c
	ts.tm_mon = ((msDate >> 5) & 0x0f) - 1;     /* Month number.     */
Packit 08bd4c
	ts.tm_mday = msDate & 0x1f;		    /* Day of month.     */
Packit 08bd4c
	ts.tm_hour = (msTime >> 11) & 0x1f;
Packit 08bd4c
	ts.tm_min = (msTime >> 5) & 0x3f;
Packit 08bd4c
	ts.tm_sec = (msTime << 1) & 0x3e;
Packit 08bd4c
	ts.tm_isdst = -1;
Packit 08bd4c
	return (mktime(&ts);;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*****************************************************************
Packit 08bd4c
 *
Packit 08bd4c
 * LZX decompression code.
Packit 08bd4c
 *
Packit 08bd4c
 *****************************************************************/
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Initialize LZX decoder.
Packit 08bd4c
 *
Packit 08bd4c
 * Returns ARCHIVE_OK if initialization was successful.
Packit 08bd4c
 * Returns ARCHIVE_FAILED if w_bits has unsupported value.
Packit 08bd4c
 * Returns ARCHIVE_FATAL if initialization failed; memory allocation
Packit 08bd4c
 * error occurred.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
lzx_decode_init(struct lzx_stream *strm, int w_bits)
Packit 08bd4c
{
Packit 08bd4c
	struct lzx_dec *ds;
Packit 08bd4c
	int slot, w_size, w_slot;
Packit 08bd4c
	int base, footer;
Packit 08bd4c
	int base_inc[18];
Packit 08bd4c
Packit 08bd4c
	if (strm->ds == NULL) {
Packit 08bd4c
		strm->ds = calloc(1, sizeof(*strm->ds));
Packit 08bd4c
		if (strm->ds == NULL)
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	ds = strm->ds;
Packit 08bd4c
	ds->error = ARCHIVE_FAILED;
Packit 08bd4c
Packit 08bd4c
	/* Allow bits from 15(32KBi) up to 21(2MBi) */
Packit 08bd4c
	if (w_bits < SLOT_BASE || w_bits > SLOT_MAX)
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
Packit 08bd4c
	ds->error = ARCHIVE_FATAL;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Alloc window
Packit 08bd4c
	 */
Packit 08bd4c
	w_size = ds->w_size;
Packit 08bd4c
	w_slot = slots[w_bits - SLOT_BASE];
Packit 08bd4c
	ds->w_size = 1U << w_bits;
Packit 08bd4c
	ds->w_mask = ds->w_size -1;
Packit 08bd4c
	if (ds->w_buff == NULL || w_size != ds->w_size) {
Packit 08bd4c
		free(ds->w_buff);
Packit 08bd4c
		ds->w_buff = malloc(ds->w_size);
Packit 08bd4c
		if (ds->w_buff == NULL)
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		free(ds->pos_tbl);
Packit 08bd4c
		ds->pos_tbl = malloc(sizeof(ds->pos_tbl[0]) * w_slot);
Packit 08bd4c
		if (ds->pos_tbl == NULL)
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		lzx_huffman_free(&(ds->mt));
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	for (footer = 0; footer < 18; footer++)
Packit 08bd4c
		base_inc[footer] = 1 << footer;
Packit 08bd4c
	base = footer = 0;
Packit 08bd4c
	for (slot = 0; slot < w_slot; slot++) {
Packit 08bd4c
		int n;
Packit 08bd4c
		if (footer == 0)
Packit 08bd4c
			base = slot;
Packit 08bd4c
		else
Packit 08bd4c
			base += base_inc[footer];
Packit 08bd4c
		if (footer < 17) {
Packit 08bd4c
			footer = -2;
Packit 08bd4c
			for (n = base; n; n >>= 1)
Packit 08bd4c
				footer++;
Packit 08bd4c
			if (footer <= 0)
Packit 08bd4c
				footer = 0;
Packit 08bd4c
		}
Packit 08bd4c
		ds->pos_tbl[slot].base = base;
Packit 08bd4c
		ds->pos_tbl[slot].footer_bits = footer;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	ds->w_pos = 0;
Packit 08bd4c
	ds->state = 0;
Packit 08bd4c
	ds->br.cache_buffer = 0;
Packit 08bd4c
	ds->br.cache_avail = 0;
Packit 08bd4c
	ds->r0 = ds->r1 = ds->r2 = 1;
Packit 08bd4c
Packit 08bd4c
	/* Initialize aligned offset tree. */
Packit 08bd4c
	if (lzx_huffman_init(&(ds->at), 8, 8) != ARCHIVE_OK)
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
Packit 08bd4c
	/* Initialize pre-tree. */
Packit 08bd4c
	if (lzx_huffman_init(&(ds->pt), 20, 10) != ARCHIVE_OK)
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
Packit 08bd4c
	/* Initialize Main tree. */
Packit 08bd4c
	if (lzx_huffman_init(&(ds->mt), 256+(w_slot<<3), 16)
Packit 08bd4c
	    != ARCHIVE_OK)
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
Packit 08bd4c
	/* Initialize Length tree. */
Packit 08bd4c
	if (lzx_huffman_init(&(ds->lt), 249, 16) != ARCHIVE_OK)
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
Packit 08bd4c
	ds->error = 0;
Packit 08bd4c
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Release LZX decoder.
Packit 08bd4c
 */
Packit 08bd4c
static void
Packit 08bd4c
lzx_decode_free(struct lzx_stream *strm)
Packit 08bd4c
{
Packit 08bd4c
Packit 08bd4c
	if (strm->ds == NULL)
Packit 08bd4c
		return;
Packit 08bd4c
	free(strm->ds->w_buff);
Packit 08bd4c
	free(strm->ds->pos_tbl);
Packit 08bd4c
	lzx_huffman_free(&(strm->ds->at));
Packit 08bd4c
	lzx_huffman_free(&(strm->ds->pt));
Packit 08bd4c
	lzx_huffman_free(&(strm->ds->mt));
Packit 08bd4c
	lzx_huffman_free(&(strm->ds->lt));
Packit 08bd4c
	free(strm->ds);
Packit 08bd4c
	strm->ds = NULL;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * E8 Call Translation reversal.
Packit 08bd4c
 */
Packit 08bd4c
static void
Packit 08bd4c
lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
Packit 08bd4c
{
Packit 08bd4c
	struct lzx_dec *ds = strm->ds;
Packit 08bd4c
	unsigned char *b, *end;
Packit 08bd4c
Packit 08bd4c
	if (!ds->translation || size <= 10)
Packit 08bd4c
		return;
Packit 08bd4c
	b = p;
Packit 08bd4c
	end = b + size - 10;
Packit 08bd4c
	while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {
Packit 08bd4c
		size_t i = b - (unsigned char *)p;
Packit 08bd4c
		int32_t cp, displacement, value;
Packit 08bd4c
Packit 08bd4c
		cp = (int32_t)(offset + (uint32_t)i);
Packit 08bd4c
		value = archive_le32dec(&b[1]);
Packit 08bd4c
		if (value >= -cp && value < (int32_t)ds->translation_size) {
Packit 08bd4c
			if (value >= 0)
Packit 08bd4c
				displacement = value - cp;
Packit 08bd4c
			else
Packit 08bd4c
				displacement = value + ds->translation_size;
Packit 08bd4c
			archive_le32enc(&b[1], (uint32_t)displacement);
Packit 08bd4c
		}
Packit 08bd4c
		b += 5;
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Bit stream reader.
Packit 08bd4c
 */
Packit 08bd4c
/* Check that the cache buffer has enough bits. */
Packit 08bd4c
#define lzx_br_has(br, n)	((br)->cache_avail >= n)
Packit 08bd4c
/* Get compressed data by bit. */
Packit 08bd4c
#define lzx_br_bits(br, n)				\
Packit 08bd4c
	(((uint32_t)((br)->cache_buffer >>		\
Packit 08bd4c
		((br)->cache_avail - (n)))) & cache_masks[n])
Packit 08bd4c
#define lzx_br_bits_forced(br, n)			\
Packit 08bd4c
	(((uint32_t)((br)->cache_buffer <<		\
Packit 08bd4c
		((n) - (br)->cache_avail))) & cache_masks[n])
Packit 08bd4c
/* Read ahead to make sure the cache buffer has enough compressed data we
Packit 08bd4c
 * will use.
Packit 08bd4c
 *  True  : completed, there is enough data in the cache buffer.
Packit 08bd4c
 *  False : we met that strm->next_in is empty, we have to get following
Packit 08bd4c
 *          bytes. */
Packit 08bd4c
#define lzx_br_read_ahead_0(strm, br, n)	\
Packit 08bd4c
	(lzx_br_has((br), (n)) || lzx_br_fillup(strm, br))
Packit 08bd4c
/*  True  : the cache buffer has some bits as much as we need.
Packit 08bd4c
 *  False : there are no enough bits in the cache buffer to be used,
Packit 08bd4c
 *          we have to get following bytes if we could. */
Packit 08bd4c
#define lzx_br_read_ahead(strm, br, n)	\
Packit 08bd4c
	(lzx_br_read_ahead_0((strm), (br), (n)) || lzx_br_has((br), (n)))
Packit 08bd4c
Packit 08bd4c
/* Notify how many bits we consumed. */
Packit 08bd4c
#define lzx_br_consume(br, n)	((br)->cache_avail -= (n))
Packit 08bd4c
#define lzx_br_consume_unaligned_bits(br) ((br)->cache_avail &= ~0x0f)
Packit 08bd4c
Packit 08bd4c
#define lzx_br_is_unaligned(br)	((br)->cache_avail & 0x0f)
Packit 08bd4c
Packit 08bd4c
static const uint32_t cache_masks[] = {
Packit 08bd4c
	0x00000000, 0x00000001, 0x00000003, 0x00000007,
Packit 08bd4c
	0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
Packit 08bd4c
	0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
Packit 08bd4c
	0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
Packit 08bd4c
	0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
Packit 08bd4c
	0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
Packit 08bd4c
	0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
Packit 08bd4c
	0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,
Packit 08bd4c
	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Shift away used bits in the cache data and fill it up with following bits.
Packit 08bd4c
 * Call this when cache buffer does not have enough bits you need.
Packit 08bd4c
 *
Packit 08bd4c
 * Returns 1 if the cache buffer is full.
Packit 08bd4c
 * Returns 0 if the cache buffer is not full; input buffer is empty.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
Packit 08bd4c
{
Packit 08bd4c
/*
Packit 08bd4c
 * x86 processor family can read misaligned data without an access error.
Packit 08bd4c
 */
Packit 08bd4c
	int n = CACHE_BITS - br->cache_avail;
Packit 08bd4c
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		switch (n >> 4) {
Packit 08bd4c
		case 4:
Packit 08bd4c
			if (strm->avail_in >= 8) {
Packit 08bd4c
				br->cache_buffer =
Packit 08bd4c
				    ((uint64_t)strm->next_in[1]) << 56 |
Packit 08bd4c
				    ((uint64_t)strm->next_in[0]) << 48 |
Packit 08bd4c
				    ((uint64_t)strm->next_in[3]) << 40 |
Packit 08bd4c
				    ((uint64_t)strm->next_in[2]) << 32 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[5]) << 24 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[4]) << 16 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[7]) << 8 |
Packit 08bd4c
				     (uint32_t)strm->next_in[6];
Packit 08bd4c
				strm->next_in += 8;
Packit 08bd4c
				strm->avail_in -= 8;
Packit 08bd4c
				br->cache_avail += 8 * 8;
Packit 08bd4c
				return (1);
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		case 3:
Packit 08bd4c
			if (strm->avail_in >= 6) {
Packit 08bd4c
				br->cache_buffer =
Packit 08bd4c
		 		   (br->cache_buffer << 48) |
Packit 08bd4c
				    ((uint64_t)strm->next_in[1]) << 40 |
Packit 08bd4c
				    ((uint64_t)strm->next_in[0]) << 32 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[3]) << 24 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[2]) << 16 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[5]) << 8 |
Packit 08bd4c
				     (uint32_t)strm->next_in[4];
Packit 08bd4c
				strm->next_in += 6;
Packit 08bd4c
				strm->avail_in -= 6;
Packit 08bd4c
				br->cache_avail += 6 * 8;
Packit 08bd4c
				return (1);
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		case 0:
Packit 08bd4c
			/* We have enough compressed data in
Packit 08bd4c
			 * the cache buffer.*/
Packit 08bd4c
			return (1);
Packit 08bd4c
		default:
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
		if (strm->avail_in < 2) {
Packit 08bd4c
			/* There is not enough compressed data to
Packit 08bd4c
			 * fill up the cache buffer. */
Packit 08bd4c
			if (strm->avail_in == 1) {
Packit 08bd4c
				br->odd = *strm->next_in++;
Packit 08bd4c
				strm->avail_in--;
Packit 08bd4c
				br->have_odd = 1;
Packit 08bd4c
			}
Packit 08bd4c
			return (0);
Packit 08bd4c
		}
Packit 08bd4c
		br->cache_buffer =
Packit 08bd4c
		   (br->cache_buffer << 16) |
Packit 08bd4c
		    archive_le16dec(strm->next_in);
Packit 08bd4c
		strm->next_in += 2;
Packit 08bd4c
		strm->avail_in -= 2;
Packit 08bd4c
		br->cache_avail += 16;
Packit 08bd4c
		n -= 16;
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static void
Packit 08bd4c
lzx_br_fixup(struct lzx_stream *strm, struct lzx_br *br)
Packit 08bd4c
{
Packit 08bd4c
	int n = CACHE_BITS - br->cache_avail;
Packit 08bd4c
Packit 08bd4c
	if (br->have_odd && n >= 16 && strm->avail_in > 0) {
Packit 08bd4c
		br->cache_buffer =
Packit 08bd4c
		   (br->cache_buffer << 16) |
Packit 08bd4c
		   ((uint16_t)(*strm->next_in)) << 8 | br->odd;
Packit 08bd4c
		strm->next_in++;
Packit 08bd4c
		strm->avail_in--;
Packit 08bd4c
		br->cache_avail += 16;
Packit 08bd4c
		br->have_odd = 0;
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static void
Packit 08bd4c
lzx_cleanup_bitstream(struct lzx_stream *strm)
Packit 08bd4c
{
Packit 08bd4c
	strm->ds->br.cache_avail = 0;
Packit 08bd4c
	strm->ds->br.have_odd = 0;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Decode LZX.
Packit 08bd4c
 *
Packit 08bd4c
 * 1. Returns ARCHIVE_OK if output buffer or input buffer are empty.
Packit 08bd4c
 *    Please set available buffer and call this function again.
Packit 08bd4c
 * 2. Returns ARCHIVE_EOF if decompression has been completed.
Packit 08bd4c
 * 3. Returns ARCHIVE_FAILED if an error occurred; compressed data
Packit 08bd4c
 *    is broken or you do not set 'last' flag properly.
Packit 08bd4c
 */
Packit 08bd4c
#define ST_RD_TRANSLATION	0
Packit 08bd4c
#define ST_RD_TRANSLATION_SIZE	1
Packit 08bd4c
#define ST_RD_BLOCK_TYPE	2
Packit 08bd4c
#define ST_RD_BLOCK_SIZE	3
Packit 08bd4c
#define ST_RD_ALIGNMENT		4
Packit 08bd4c
#define ST_RD_R0		5
Packit 08bd4c
#define ST_RD_R1		6
Packit 08bd4c
#define ST_RD_R2		7
Packit 08bd4c
#define ST_COPY_UNCOMP1		8
Packit 08bd4c
#define ST_COPY_UNCOMP2		9
Packit 08bd4c
#define ST_RD_ALIGNED_OFFSET	10
Packit 08bd4c
#define ST_RD_VERBATIM		11
Packit 08bd4c
#define ST_RD_PRE_MAIN_TREE_256	12
Packit 08bd4c
#define ST_MAIN_TREE_256	13
Packit 08bd4c
#define ST_RD_PRE_MAIN_TREE_REM	14
Packit 08bd4c
#define ST_MAIN_TREE_REM	15
Packit 08bd4c
#define ST_RD_PRE_LENGTH_TREE	16
Packit 08bd4c
#define ST_LENGTH_TREE		17
Packit 08bd4c
#define ST_MAIN			18
Packit 08bd4c
#define ST_LENGTH		19
Packit 08bd4c
#define ST_OFFSET		20
Packit 08bd4c
#define ST_REAL_POS		21
Packit 08bd4c
#define ST_COPY			22
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
lzx_decode(struct lzx_stream *strm, int last)
Packit 08bd4c
{
Packit 08bd4c
	struct lzx_dec *ds = strm->ds;
Packit 08bd4c
	int64_t avail_in;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	if (ds->error)
Packit 08bd4c
		return (ds->error);
Packit 08bd4c
Packit 08bd4c
	avail_in = strm->avail_in;
Packit 08bd4c
	lzx_br_fixup(strm, &(ds->br));
Packit 08bd4c
	do {
Packit 08bd4c
		if (ds->state < ST_MAIN)
Packit 08bd4c
			r = lzx_read_blocks(strm, last);
Packit 08bd4c
		else {
Packit 08bd4c
			int64_t bytes_written = strm->avail_out;
Packit 08bd4c
			r = lzx_decode_blocks(strm, last);
Packit 08bd4c
			bytes_written -= strm->avail_out;
Packit 08bd4c
			strm->next_out += bytes_written;
Packit 08bd4c
			strm->total_out += bytes_written;
Packit 08bd4c
		}
Packit 08bd4c
	} while (r == 100);
Packit 08bd4c
	strm->total_in += avail_in - strm->avail_in;
Packit 08bd4c
	return (r);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
lzx_read_blocks(struct lzx_stream *strm, int last)
Packit 08bd4c
{
Packit 08bd4c
	struct lzx_dec *ds = strm->ds;
Packit 08bd4c
	struct lzx_br *br = &(ds->br);
Packit 08bd4c
	int i, r;
Packit 08bd4c
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		switch (ds->state) {
Packit 08bd4c
		case ST_RD_TRANSLATION:
Packit 08bd4c
			if (!lzx_br_read_ahead(strm, br, 1)) {
Packit 08bd4c
				ds->state = ST_RD_TRANSLATION;
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			ds->translation = lzx_br_bits(br, 1);
Packit 08bd4c
			lzx_br_consume(br, 1);
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_TRANSLATION_SIZE:
Packit 08bd4c
			if (ds->translation) {
Packit 08bd4c
				if (!lzx_br_read_ahead(strm, br, 32)) {
Packit 08bd4c
					ds->state = ST_RD_TRANSLATION_SIZE;
Packit 08bd4c
					if (last)
Packit 08bd4c
						goto failed;
Packit 08bd4c
					return (ARCHIVE_OK);
Packit 08bd4c
				}
Packit 08bd4c
				ds->translation_size = lzx_br_bits(br, 16);
Packit 08bd4c
				lzx_br_consume(br, 16);
Packit 08bd4c
				ds->translation_size <<= 16;
Packit 08bd4c
				ds->translation_size |= lzx_br_bits(br, 16);
Packit 08bd4c
				lzx_br_consume(br, 16);
Packit 08bd4c
			}
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_BLOCK_TYPE:
Packit 08bd4c
			if (!lzx_br_read_ahead(strm, br, 3)) {
Packit 08bd4c
				ds->state = ST_RD_BLOCK_TYPE;
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			ds->block_type = lzx_br_bits(br, 3);
Packit 08bd4c
			lzx_br_consume(br, 3);
Packit 08bd4c
			/* Check a block type. */
Packit 08bd4c
			switch (ds->block_type) {
Packit 08bd4c
			case VERBATIM_BLOCK:
Packit 08bd4c
			case ALIGNED_OFFSET_BLOCK:
Packit 08bd4c
			case UNCOMPRESSED_BLOCK:
Packit 08bd4c
				break;
Packit 08bd4c
			default:
Packit 08bd4c
				goto failed;/* Invalid */
Packit 08bd4c
			}
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_BLOCK_SIZE:
Packit 08bd4c
			if (!lzx_br_read_ahead(strm, br, 24)) {
Packit 08bd4c
				ds->state = ST_RD_BLOCK_SIZE;
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			ds->block_size = lzx_br_bits(br, 8);
Packit 08bd4c
			lzx_br_consume(br, 8);
Packit 08bd4c
			ds->block_size <<= 16;
Packit 08bd4c
			ds->block_size |= lzx_br_bits(br, 16);
Packit 08bd4c
			lzx_br_consume(br, 16);
Packit 08bd4c
			if (ds->block_size == 0)
Packit 08bd4c
				goto failed;
Packit 08bd4c
			ds->block_bytes_avail = ds->block_size;
Packit 08bd4c
			if (ds->block_type != UNCOMPRESSED_BLOCK) {
Packit 08bd4c
				if (ds->block_type == VERBATIM_BLOCK)
Packit 08bd4c
					ds->state = ST_RD_VERBATIM;
Packit 08bd4c
				else
Packit 08bd4c
					ds->state = ST_RD_ALIGNED_OFFSET;
Packit 08bd4c
				break;
Packit 08bd4c
			}
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_ALIGNMENT:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Handle an Uncompressed Block.
Packit 08bd4c
			 */
Packit 08bd4c
			/* Skip padding to align following field on
Packit 08bd4c
			 * 16-bit boundary. */
Packit 08bd4c
			if (lzx_br_is_unaligned(br))
Packit 08bd4c
				lzx_br_consume_unaligned_bits(br);
Packit 08bd4c
			else {
Packit 08bd4c
				if (lzx_br_read_ahead(strm, br, 16))
Packit 08bd4c
					lzx_br_consume(br, 16);
Packit 08bd4c
				else {
Packit 08bd4c
					ds->state = ST_RD_ALIGNMENT;
Packit 08bd4c
					if (last)
Packit 08bd4c
						goto failed;
Packit 08bd4c
					return (ARCHIVE_OK);
Packit 08bd4c
				}
Packit 08bd4c
			}
Packit 08bd4c
			/* Preparation to read repeated offsets R0,R1 and R2. */
Packit 08bd4c
			ds->rbytes_avail = 0;
Packit 08bd4c
			ds->state = ST_RD_R0;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_R0:
Packit 08bd4c
		case ST_RD_R1:
Packit 08bd4c
		case ST_RD_R2:
Packit 08bd4c
			do {
Packit 08bd4c
				uint16_t u16;
Packit 08bd4c
				/* Drain bits in the cache buffer of
Packit 08bd4c
				 * bit-stream. */
Packit 08bd4c
				if (lzx_br_has(br, 32)) {
Packit 08bd4c
					u16 = lzx_br_bits(br, 16);
Packit 08bd4c
					lzx_br_consume(br, 16);
Packit 08bd4c
					archive_le16enc(ds->rbytes, u16);
Packit 08bd4c
					u16 = lzx_br_bits(br, 16);
Packit 08bd4c
					lzx_br_consume(br, 16);
Packit 08bd4c
					archive_le16enc(ds->rbytes+2, u16);
Packit 08bd4c
					ds->rbytes_avail = 4;
Packit 08bd4c
				} else if (lzx_br_has(br, 16)) {
Packit 08bd4c
					u16 = lzx_br_bits(br, 16);
Packit 08bd4c
					lzx_br_consume(br, 16);
Packit 08bd4c
					archive_le16enc(ds->rbytes, u16);
Packit 08bd4c
					ds->rbytes_avail = 2;
Packit 08bd4c
				}
Packit 08bd4c
				if (ds->rbytes_avail < 4 && ds->br.have_odd) {
Packit 08bd4c
					ds->rbytes[ds->rbytes_avail++] =
Packit 08bd4c
					    ds->br.odd;
Packit 08bd4c
					ds->br.have_odd = 0;
Packit 08bd4c
				}
Packit 08bd4c
				while (ds->rbytes_avail < 4) {
Packit 08bd4c
					if (strm->avail_in <= 0) {
Packit 08bd4c
						if (last)
Packit 08bd4c
							goto failed;
Packit 08bd4c
						return (ARCHIVE_OK);
Packit 08bd4c
					}
Packit 08bd4c
					ds->rbytes[ds->rbytes_avail++] =
Packit 08bd4c
					    *strm->next_in++;
Packit 08bd4c
					strm->avail_in--;
Packit 08bd4c
				}
Packit 08bd4c
				ds->rbytes_avail = 0;
Packit 08bd4c
				if (ds->state == ST_RD_R0) {
Packit 08bd4c
					ds->r0 = archive_le32dec(ds->rbytes);
Packit 08bd4c
					if (ds->r0 < 0)
Packit 08bd4c
						goto failed;
Packit 08bd4c
					ds->state = ST_RD_R1;
Packit 08bd4c
				} else if (ds->state == ST_RD_R1) {
Packit 08bd4c
					ds->r1 = archive_le32dec(ds->rbytes);
Packit 08bd4c
					if (ds->r1 < 0)
Packit 08bd4c
						goto failed;
Packit 08bd4c
					ds->state = ST_RD_R2;
Packit 08bd4c
				} else if (ds->state == ST_RD_R2) {
Packit 08bd4c
					ds->r2 = archive_le32dec(ds->rbytes);
Packit 08bd4c
					if (ds->r2 < 0)
Packit 08bd4c
						goto failed;
Packit 08bd4c
					/* We've gotten all repeated offsets. */
Packit 08bd4c
					ds->state = ST_COPY_UNCOMP1;
Packit 08bd4c
				}
Packit 08bd4c
			} while (ds->state != ST_COPY_UNCOMP1);
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_COPY_UNCOMP1:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Copy bytes form next_in to next_out directly.
Packit 08bd4c
			 */
Packit 08bd4c
			while (ds->block_bytes_avail) {
Packit 08bd4c
				int l;
Packit 08bd4c
Packit 08bd4c
				if (strm->avail_out <= 0)
Packit 08bd4c
					/* Output buffer is empty. */
Packit 08bd4c
					return (ARCHIVE_OK);
Packit 08bd4c
				if (strm->avail_in <= 0) {
Packit 08bd4c
					/* Input buffer is empty. */
Packit 08bd4c
					if (last)
Packit 08bd4c
						goto failed;
Packit 08bd4c
					return (ARCHIVE_OK);
Packit 08bd4c
				}
Packit 08bd4c
				l = (int)ds->block_bytes_avail;
Packit 08bd4c
				if (l > ds->w_size - ds->w_pos)
Packit 08bd4c
					l = ds->w_size - ds->w_pos;
Packit 08bd4c
				if (l > strm->avail_out)
Packit 08bd4c
					l = (int)strm->avail_out;
Packit 08bd4c
				if (l > strm->avail_in)
Packit 08bd4c
					l = (int)strm->avail_in;
Packit 08bd4c
				memcpy(strm->next_out, strm->next_in, l);
Packit 08bd4c
				memcpy(&(ds->w_buff[ds->w_pos]),
Packit 08bd4c
				    strm->next_in, l);
Packit 08bd4c
				strm->next_in += l;
Packit 08bd4c
				strm->avail_in -= l;
Packit 08bd4c
				strm->next_out += l;
Packit 08bd4c
				strm->avail_out -= l;
Packit 08bd4c
				strm->total_out += l;
Packit 08bd4c
				ds->w_pos = (ds->w_pos + l) & ds->w_mask;
Packit 08bd4c
				ds->block_bytes_avail -= l;
Packit 08bd4c
			}
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_COPY_UNCOMP2:
Packit 08bd4c
			/* Re-align; skip padding byte. */
Packit 08bd4c
			if (ds->block_size & 1) {
Packit 08bd4c
				if (strm->avail_in <= 0) {
Packit 08bd4c
					/* Input buffer is empty. */
Packit 08bd4c
					ds->state = ST_COPY_UNCOMP2;
Packit 08bd4c
					if (last)
Packit 08bd4c
						goto failed;
Packit 08bd4c
					return (ARCHIVE_OK);
Packit 08bd4c
				}
Packit 08bd4c
				strm->next_in++;
Packit 08bd4c
				strm->avail_in --;
Packit 08bd4c
			}
Packit 08bd4c
			/* This block ended. */
Packit 08bd4c
			ds->state = ST_RD_BLOCK_TYPE;
Packit 08bd4c
			return (ARCHIVE_EOF);
Packit 08bd4c
			/********************/
Packit 08bd4c
		case ST_RD_ALIGNED_OFFSET:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Read Aligned offset tree.
Packit 08bd4c
			 */
Packit 08bd4c
			if (!lzx_br_read_ahead(strm, br, 3 * ds->at.len_size)) {
Packit 08bd4c
				ds->state = ST_RD_ALIGNED_OFFSET;
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			memset(ds->at.freq, 0, sizeof(ds->at.freq));
Packit 08bd4c
			for (i = 0; i < ds->at.len_size; i++) {
Packit 08bd4c
				ds->at.bitlen[i] = lzx_br_bits(br, 3);
Packit 08bd4c
				ds->at.freq[ds->at.bitlen[i]]++;
Packit 08bd4c
				lzx_br_consume(br, 3);
Packit 08bd4c
			}
Packit 08bd4c
			if (!lzx_make_huffman_table(&ds->at))
Packit 08bd4c
				goto failed;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_VERBATIM:
Packit 08bd4c
			ds->loop = 0;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_PRE_MAIN_TREE_256:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Read Pre-tree for first 256 elements of main tree.
Packit 08bd4c
			 */
Packit 08bd4c
			if (!lzx_read_pre_tree(strm)) {
Packit 08bd4c
				ds->state = ST_RD_PRE_MAIN_TREE_256;
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			if (!lzx_make_huffman_table(&ds->pt))
Packit 08bd4c
				goto failed;
Packit 08bd4c
			ds->loop = 0;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_MAIN_TREE_256:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Get path lengths of first 256 elements of main tree.
Packit 08bd4c
			 */
Packit 08bd4c
			r = lzx_read_bitlen(strm, &ds->mt, 256);
Packit 08bd4c
			if (r < 0)
Packit 08bd4c
				goto failed;
Packit 08bd4c
			else if (!r) {
Packit 08bd4c
				ds->state = ST_MAIN_TREE_256;
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			ds->loop = 0;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_PRE_MAIN_TREE_REM:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Read Pre-tree for remaining elements of main tree.
Packit 08bd4c
			 */
Packit 08bd4c
			if (!lzx_read_pre_tree(strm)) {
Packit 08bd4c
				ds->state = ST_RD_PRE_MAIN_TREE_REM;
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			if (!lzx_make_huffman_table(&ds->pt))
Packit 08bd4c
				goto failed;
Packit 08bd4c
			ds->loop = 256;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_MAIN_TREE_REM:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Get path lengths of remaining elements of main tree.
Packit 08bd4c
			 */
Packit 08bd4c
			r = lzx_read_bitlen(strm, &ds->mt, -1);
Packit 08bd4c
			if (r < 0)
Packit 08bd4c
				goto failed;
Packit 08bd4c
			else if (!r) {
Packit 08bd4c
				ds->state = ST_MAIN_TREE_REM;
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			if (!lzx_make_huffman_table(&ds->mt))
Packit 08bd4c
				goto failed;
Packit 08bd4c
			ds->loop = 0;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_PRE_LENGTH_TREE:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Read Pre-tree for remaining elements of main tree.
Packit 08bd4c
			 */
Packit 08bd4c
			if (!lzx_read_pre_tree(strm)) {
Packit 08bd4c
				ds->state = ST_RD_PRE_LENGTH_TREE;
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			if (!lzx_make_huffman_table(&ds->pt))
Packit 08bd4c
				goto failed;
Packit 08bd4c
			ds->loop = 0;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_LENGTH_TREE:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Get path lengths of remaining elements of main tree.
Packit 08bd4c
			 */
Packit 08bd4c
			r = lzx_read_bitlen(strm, &ds->lt, -1);
Packit 08bd4c
			if (r < 0)
Packit 08bd4c
				goto failed;
Packit 08bd4c
			else if (!r) {
Packit 08bd4c
				ds->state = ST_LENGTH_TREE;
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			if (!lzx_make_huffman_table(&ds->lt))
Packit 08bd4c
				goto failed;
Packit 08bd4c
			ds->state = ST_MAIN;
Packit 08bd4c
			return (100);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
failed:
Packit 08bd4c
	return (ds->error = ARCHIVE_FAILED);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
lzx_decode_blocks(struct lzx_stream *strm, int last)
Packit 08bd4c
{
Packit 08bd4c
	struct lzx_dec *ds = strm->ds;
Packit 08bd4c
	struct lzx_br bre = ds->br;
Packit 08bd4c
	struct huffman *at = &(ds->at), *lt = &(ds->lt), *mt = &(ds->mt);
Packit 08bd4c
	const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;
Packit 08bd4c
	unsigned char *noutp = strm->next_out;
Packit 08bd4c
	unsigned char *endp = noutp + strm->avail_out;
Packit 08bd4c
	unsigned char *w_buff = ds->w_buff;
Packit 08bd4c
	unsigned char *at_bitlen = at->bitlen;
Packit 08bd4c
	unsigned char *lt_bitlen = lt->bitlen;
Packit 08bd4c
	unsigned char *mt_bitlen = mt->bitlen;
Packit 08bd4c
	size_t block_bytes_avail = ds->block_bytes_avail;
Packit 08bd4c
	int at_max_bits = at->max_bits;
Packit 08bd4c
	int lt_max_bits = lt->max_bits;
Packit 08bd4c
	int mt_max_bits = mt->max_bits;
Packit 08bd4c
	int c, copy_len = ds->copy_len, copy_pos = ds->copy_pos;
Packit 08bd4c
	int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
Packit 08bd4c
	int length_header = ds->length_header;
Packit 08bd4c
	int offset_bits = ds->offset_bits;
Packit 08bd4c
	int position_slot = ds->position_slot;
Packit 08bd4c
	int r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;
Packit 08bd4c
	int state = ds->state;
Packit 08bd4c
	char block_type = ds->block_type;
Packit 08bd4c
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		switch (state) {
Packit 08bd4c
		case ST_MAIN:
Packit 08bd4c
			for (;;) {
Packit 08bd4c
				if (block_bytes_avail == 0) {
Packit 08bd4c
					/* This block ended. */
Packit 08bd4c
					ds->state = ST_RD_BLOCK_TYPE;
Packit 08bd4c
					ds->br = bre;
Packit 08bd4c
					ds->block_bytes_avail =
Packit 08bd4c
					    block_bytes_avail;
Packit 08bd4c
					ds->copy_len = copy_len;
Packit 08bd4c
					ds->copy_pos = copy_pos;
Packit 08bd4c
					ds->length_header = length_header;
Packit 08bd4c
					ds->position_slot = position_slot;
Packit 08bd4c
					ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
Packit 08bd4c
					ds->w_pos = w_pos;
Packit 08bd4c
					strm->avail_out = endp - noutp;
Packit 08bd4c
					return (ARCHIVE_EOF);
Packit 08bd4c
				}
Packit 08bd4c
				if (noutp >= endp)
Packit 08bd4c
					/* Output buffer is empty. */
Packit 08bd4c
					goto next_data;
Packit 08bd4c
Packit 08bd4c
				if (!lzx_br_read_ahead(strm, &bre,
Packit 08bd4c
				    mt_max_bits)) {
Packit 08bd4c
					if (!last)
Packit 08bd4c
						goto next_data;
Packit 08bd4c
					/* Remaining bits are less than
Packit 08bd4c
					 * maximum bits(mt.max_bits) but maybe
Packit 08bd4c
					 * it still remains as much as we need,
Packit 08bd4c
					 * so we should try to use it with
Packit 08bd4c
					 * dummy bits. */
Packit 08bd4c
					c = lzx_decode_huffman(mt,
Packit 08bd4c
					      lzx_br_bits_forced(
Packit 08bd4c
				 	        &bre, mt_max_bits));
Packit 08bd4c
					lzx_br_consume(&bre, mt_bitlen[c]);
Packit 08bd4c
					if (!lzx_br_has(&bre, 0))
Packit 08bd4c
						goto failed;/* Over read. */
Packit 08bd4c
				} else {
Packit 08bd4c
					c = lzx_decode_huffman(mt,
Packit 08bd4c
					      lzx_br_bits(&bre, mt_max_bits));
Packit 08bd4c
					lzx_br_consume(&bre, mt_bitlen[c]);
Packit 08bd4c
				}
Packit 08bd4c
				if (c > UCHAR_MAX)
Packit 08bd4c
					break;
Packit 08bd4c
				/*
Packit 08bd4c
				 * 'c' is exactly literal code.
Packit 08bd4c
				 */
Packit 08bd4c
				/* Save a decoded code to reference it
Packit 08bd4c
				 * afterward. */
Packit 08bd4c
				w_buff[w_pos] = c;
Packit 08bd4c
				w_pos = (w_pos + 1) & w_mask;
Packit 08bd4c
				/* Store the decoded code to output buffer. */
Packit 08bd4c
				*noutp++ = c;
Packit 08bd4c
				block_bytes_avail--;
Packit 08bd4c
			}
Packit 08bd4c
			/*
Packit 08bd4c
			 * Get a match code, its length and offset.
Packit 08bd4c
			 */
Packit 08bd4c
			c -= UCHAR_MAX + 1;
Packit 08bd4c
			length_header = c & 7;
Packit 08bd4c
			position_slot = c >> 3;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_LENGTH:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Get a length.
Packit 08bd4c
			 */
Packit 08bd4c
			if (length_header == 7) {
Packit 08bd4c
				if (!lzx_br_read_ahead(strm, &bre,
Packit 08bd4c
				    lt_max_bits)) {
Packit 08bd4c
					if (!last) {
Packit 08bd4c
						state = ST_LENGTH;
Packit 08bd4c
						goto next_data;
Packit 08bd4c
					}
Packit 08bd4c
					c = lzx_decode_huffman(lt,
Packit 08bd4c
					      lzx_br_bits_forced(
Packit 08bd4c
					        &bre, lt_max_bits));
Packit 08bd4c
					lzx_br_consume(&bre, lt_bitlen[c]);
Packit 08bd4c
					if (!lzx_br_has(&bre, 0))
Packit 08bd4c
						goto failed;/* Over read. */
Packit 08bd4c
				} else {
Packit 08bd4c
					c = lzx_decode_huffman(lt,
Packit 08bd4c
					    lzx_br_bits(&bre, lt_max_bits));
Packit 08bd4c
					lzx_br_consume(&bre, lt_bitlen[c]);
Packit 08bd4c
				}
Packit 08bd4c
				copy_len = c + 7 + 2;
Packit 08bd4c
			} else
Packit 08bd4c
				copy_len = length_header + 2;
Packit 08bd4c
			if ((size_t)copy_len > block_bytes_avail)
Packit 08bd4c
				goto failed;
Packit 08bd4c
			/*
Packit 08bd4c
			 * Get an offset.
Packit 08bd4c
			 */
Packit 08bd4c
			switch (position_slot) {
Packit 08bd4c
			case 0: /* Use repeated offset 0. */
Packit 08bd4c
				copy_pos = r0;
Packit 08bd4c
				state = ST_REAL_POS;
Packit 08bd4c
				continue;
Packit 08bd4c
			case 1: /* Use repeated offset 1. */
Packit 08bd4c
				copy_pos = r1;
Packit 08bd4c
				/* Swap repeated offset. */
Packit 08bd4c
				r1 = r0;
Packit 08bd4c
				r0 = copy_pos;
Packit 08bd4c
				state = ST_REAL_POS;
Packit 08bd4c
				continue;
Packit 08bd4c
			case 2: /* Use repeated offset 2. */
Packit 08bd4c
				copy_pos = r2;
Packit 08bd4c
				/* Swap repeated offset. */
Packit 08bd4c
				r2 = r0;
Packit 08bd4c
				r0 = copy_pos;
Packit 08bd4c
				state = ST_REAL_POS;
Packit 08bd4c
				continue;
Packit 08bd4c
			default:
Packit 08bd4c
				offset_bits =
Packit 08bd4c
				    pos_tbl[position_slot].footer_bits;
Packit 08bd4c
				break;
Packit 08bd4c
			}
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_OFFSET:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Get the offset, which is a distance from
Packit 08bd4c
			 * current window position.
Packit 08bd4c
			 */
Packit 08bd4c
			if (block_type == ALIGNED_OFFSET_BLOCK &&
Packit 08bd4c
			    offset_bits >= 3) {
Packit 08bd4c
				int offbits = offset_bits - 3;
Packit 08bd4c
Packit 08bd4c
				if (!lzx_br_read_ahead(strm, &bre, offbits)) {
Packit 08bd4c
					state = ST_OFFSET;
Packit 08bd4c
					if (last)
Packit 08bd4c
						goto failed;
Packit 08bd4c
					goto next_data;
Packit 08bd4c
				}
Packit 08bd4c
				copy_pos = lzx_br_bits(&bre, offbits) << 3;
Packit 08bd4c
Packit 08bd4c
				/* Get an aligned number. */
Packit 08bd4c
				if (!lzx_br_read_ahead(strm, &bre,
Packit 08bd4c
				    offbits + at_max_bits)) {
Packit 08bd4c
					if (!last) {
Packit 08bd4c
						state = ST_OFFSET;
Packit 08bd4c
						goto next_data;
Packit 08bd4c
					}
Packit 08bd4c
					lzx_br_consume(&bre, offbits);
Packit 08bd4c
					c = lzx_decode_huffman(at,
Packit 08bd4c
					      lzx_br_bits_forced(&bre,
Packit 08bd4c
					        at_max_bits));
Packit 08bd4c
					lzx_br_consume(&bre, at_bitlen[c]);
Packit 08bd4c
					if (!lzx_br_has(&bre, 0))
Packit 08bd4c
						goto failed;/* Over read. */
Packit 08bd4c
				} else {
Packit 08bd4c
					lzx_br_consume(&bre, offbits);
Packit 08bd4c
					c = lzx_decode_huffman(at,
Packit 08bd4c
					      lzx_br_bits(&bre, at_max_bits));
Packit 08bd4c
					lzx_br_consume(&bre, at_bitlen[c]);
Packit 08bd4c
				}
Packit 08bd4c
				/* Add an aligned number. */
Packit 08bd4c
				copy_pos += c;
Packit 08bd4c
			} else {
Packit 08bd4c
				if (!lzx_br_read_ahead(strm, &bre,
Packit 08bd4c
				    offset_bits)) {
Packit 08bd4c
					state = ST_OFFSET;
Packit 08bd4c
					if (last)
Packit 08bd4c
						goto failed;
Packit 08bd4c
					goto next_data;
Packit 08bd4c
				}
Packit 08bd4c
				copy_pos = lzx_br_bits(&bre, offset_bits);
Packit 08bd4c
				lzx_br_consume(&bre, offset_bits);
Packit 08bd4c
			}
Packit 08bd4c
			copy_pos += pos_tbl[position_slot].base -2;
Packit 08bd4c
Packit 08bd4c
			/* Update repeated offset LRU queue. */
Packit 08bd4c
			r2 = r1;
Packit 08bd4c
			r1 = r0;
Packit 08bd4c
			r0 = copy_pos;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_REAL_POS:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Compute a real position in window.
Packit 08bd4c
			 */
Packit 08bd4c
			copy_pos = (w_pos - copy_pos) & w_mask;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_COPY:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Copy several bytes as extracted data from the window
Packit 08bd4c
			 * into the output buffer.
Packit 08bd4c
			 */
Packit 08bd4c
			for (;;) {
Packit 08bd4c
				const unsigned char *s;
Packit 08bd4c
				int l;
Packit 08bd4c
Packit 08bd4c
				l = copy_len;
Packit 08bd4c
				if (copy_pos > w_pos) {
Packit 08bd4c
					if (l > w_size - copy_pos)
Packit 08bd4c
						l = w_size - copy_pos;
Packit 08bd4c
				} else {
Packit 08bd4c
					if (l > w_size - w_pos)
Packit 08bd4c
						l = w_size - w_pos;
Packit 08bd4c
				}
Packit 08bd4c
				if (noutp + l >= endp)
Packit 08bd4c
					l = (int)(endp - noutp);
Packit 08bd4c
				s = w_buff + copy_pos;
Packit 08bd4c
				if (l >= 8 && ((copy_pos + l < w_pos)
Packit 08bd4c
				  || (w_pos + l < copy_pos))) {
Packit 08bd4c
					memcpy(w_buff + w_pos, s, l);
Packit 08bd4c
					memcpy(noutp, s, l);
Packit 08bd4c
				} else {
Packit 08bd4c
					unsigned char *d;
Packit 08bd4c
					int li;
Packit 08bd4c
Packit 08bd4c
					d = w_buff + w_pos;
Packit 08bd4c
					for (li = 0; li < l; li++)
Packit 08bd4c
						noutp[li] = d[li] = s[li];
Packit 08bd4c
				}
Packit 08bd4c
				noutp += l;
Packit 08bd4c
				copy_pos = (copy_pos + l) & w_mask;
Packit 08bd4c
				w_pos = (w_pos + l) & w_mask;
Packit 08bd4c
				block_bytes_avail -= l;
Packit 08bd4c
				if (copy_len <= l)
Packit 08bd4c
					/* A copy of current pattern ended. */
Packit 08bd4c
					break;
Packit 08bd4c
				copy_len -= l;
Packit 08bd4c
				if (noutp >= endp) {
Packit 08bd4c
					/* Output buffer is empty. */
Packit 08bd4c
					state = ST_COPY;
Packit 08bd4c
					goto next_data;
Packit 08bd4c
				}
Packit 08bd4c
			}
Packit 08bd4c
			state = ST_MAIN;
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
failed:
Packit 08bd4c
	return (ds->error = ARCHIVE_FAILED);
Packit 08bd4c
next_data:
Packit 08bd4c
	ds->br = bre;
Packit 08bd4c
	ds->block_bytes_avail = block_bytes_avail;
Packit 08bd4c
	ds->copy_len = copy_len;
Packit 08bd4c
	ds->copy_pos = copy_pos;
Packit 08bd4c
	ds->length_header = length_header;
Packit 08bd4c
	ds->offset_bits = offset_bits;
Packit 08bd4c
	ds->position_slot = position_slot;
Packit 08bd4c
	ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
Packit 08bd4c
	ds->state = state;
Packit 08bd4c
	ds->w_pos = w_pos;
Packit 08bd4c
	strm->avail_out = endp - noutp;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
lzx_read_pre_tree(struct lzx_stream *strm)
Packit 08bd4c
{
Packit 08bd4c
	struct lzx_dec *ds = strm->ds;
Packit 08bd4c
	struct lzx_br *br = &(ds->br);
Packit 08bd4c
	int i;
Packit 08bd4c
Packit 08bd4c
	if (ds->loop == 0)
Packit 08bd4c
		memset(ds->pt.freq, 0, sizeof(ds->pt.freq));
Packit 08bd4c
	for (i = ds->loop; i < ds->pt.len_size; i++) {
Packit 08bd4c
		if (!lzx_br_read_ahead(strm, br, 4)) {
Packit 08bd4c
			ds->loop = i;
Packit 08bd4c
			return (0);
Packit 08bd4c
		}
Packit 08bd4c
		ds->pt.bitlen[i] = lzx_br_bits(br, 4);
Packit 08bd4c
		ds->pt.freq[ds->pt.bitlen[i]]++;
Packit 08bd4c
		lzx_br_consume(br, 4);
Packit 08bd4c
	}
Packit 08bd4c
	ds->loop = i;
Packit 08bd4c
	return (1);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Read a bunch of bit-lengths from pre-tree.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, int end)
Packit 08bd4c
{
Packit 08bd4c
	struct lzx_dec *ds = strm->ds;
Packit 08bd4c
	struct lzx_br *br = &(ds->br);
Packit 08bd4c
	int c, i, j, ret, same;
Packit 08bd4c
	unsigned rbits;
Packit 08bd4c
Packit 08bd4c
	i = ds->loop;
Packit 08bd4c
	if (i == 0)
Packit 08bd4c
		memset(d->freq, 0, sizeof(d->freq));
Packit 08bd4c
	ret = 0;
Packit 08bd4c
	if (end < 0)
Packit 08bd4c
		end = d->len_size;
Packit 08bd4c
	while (i < end) {
Packit 08bd4c
		ds->loop = i;
Packit 08bd4c
		if (!lzx_br_read_ahead(strm, br, ds->pt.max_bits))
Packit 08bd4c
			goto getdata;
Packit 08bd4c
		rbits = lzx_br_bits(br, ds->pt.max_bits);
Packit 08bd4c
		c = lzx_decode_huffman(&(ds->pt), rbits);
Packit 08bd4c
		switch (c) {
Packit 08bd4c
		case 17:/* several zero lengths, from 4 to 19. */
Packit 08bd4c
			if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+4))
Packit 08bd4c
				goto getdata;
Packit 08bd4c
			lzx_br_consume(br, ds->pt.bitlen[c]);
Packit 08bd4c
			same = lzx_br_bits(br, 4) + 4;
Packit 08bd4c
			if (i + same > end)
Packit 08bd4c
				return (-1);/* Invalid */
Packit 08bd4c
			lzx_br_consume(br, 4);
Packit 08bd4c
			for (j = 0; j < same; j++)
Packit 08bd4c
				d->bitlen[i++] = 0;
Packit 08bd4c
			break;
Packit 08bd4c
		case 18:/* many zero lengths, from 20 to 51. */
Packit 08bd4c
			if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+5))
Packit 08bd4c
				goto getdata;
Packit 08bd4c
			lzx_br_consume(br, ds->pt.bitlen[c]);
Packit 08bd4c
			same = lzx_br_bits(br, 5) + 20;
Packit 08bd4c
			if (i + same > end)
Packit 08bd4c
				return (-1);/* Invalid */
Packit 08bd4c
			lzx_br_consume(br, 5);
Packit 08bd4c
			memset(d->bitlen + i, 0, same);
Packit 08bd4c
			i += same;
Packit 08bd4c
			break;
Packit 08bd4c
		case 19:/* a few same lengths. */
Packit 08bd4c
			if (!lzx_br_read_ahead(strm, br,
Packit 08bd4c
			    ds->pt.bitlen[c]+1+ds->pt.max_bits))
Packit 08bd4c
				goto getdata;
Packit 08bd4c
			lzx_br_consume(br, ds->pt.bitlen[c]);
Packit 08bd4c
			same = lzx_br_bits(br, 1) + 4;
Packit 08bd4c
			if (i + same > end)
Packit 08bd4c
				return (-1);
Packit 08bd4c
			lzx_br_consume(br, 1);
Packit 08bd4c
			rbits = lzx_br_bits(br, ds->pt.max_bits);
Packit 08bd4c
			c = lzx_decode_huffman(&(ds->pt), rbits);
Packit 08bd4c
			lzx_br_consume(br, ds->pt.bitlen[c]);
Packit 08bd4c
			c = (d->bitlen[i] - c + 17) % 17;
Packit 08bd4c
			if (c < 0)
Packit 08bd4c
				return (-1);/* Invalid */
Packit 08bd4c
			for (j = 0; j < same; j++)
Packit 08bd4c
				d->bitlen[i++] = c;
Packit 08bd4c
			d->freq[c] += same;
Packit 08bd4c
			break;
Packit 08bd4c
		default:
Packit 08bd4c
			lzx_br_consume(br, ds->pt.bitlen[c]);
Packit 08bd4c
			c = (d->bitlen[i] - c + 17) % 17;
Packit 08bd4c
			if (c < 0)
Packit 08bd4c
				return (-1);/* Invalid */
Packit 08bd4c
			d->freq[c]++;
Packit 08bd4c
			d->bitlen[i++] = c;
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	ret = 1;
Packit 08bd4c
getdata:
Packit 08bd4c
	ds->loop = i;
Packit 08bd4c
	return (ret);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
Packit 08bd4c
{
Packit 08bd4c
Packit 08bd4c
	if (hf->bitlen == NULL || hf->len_size != (int)len_size) {
Packit 08bd4c
		free(hf->bitlen);
Packit 08bd4c
		hf->bitlen = calloc(len_size,  sizeof(hf->bitlen[0]));
Packit 08bd4c
		if (hf->bitlen == NULL)
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		hf->len_size = (int)len_size;
Packit 08bd4c
	} else
Packit 08bd4c
		memset(hf->bitlen, 0, len_size *  sizeof(hf->bitlen[0]));
Packit 08bd4c
	if (hf->tbl == NULL) {
Packit 08bd4c
		hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0]));
Packit 08bd4c
		if (hf->tbl == NULL)
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		hf->tbl_bits = tbl_bits;
Packit 08bd4c
	}
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static void
Packit 08bd4c
lzx_huffman_free(struct huffman *hf)
Packit 08bd4c
{
Packit 08bd4c
	free(hf->bitlen);
Packit 08bd4c
	free(hf->tbl);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Make a huffman coding table.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
lzx_make_huffman_table(struct huffman *hf)
Packit 08bd4c
{
Packit 08bd4c
	uint16_t *tbl;
Packit 08bd4c
	const unsigned char *bitlen;
Packit 08bd4c
	int bitptn[17], weight[17];
Packit 08bd4c
	int i, maxbits = 0, ptn, tbl_size, w;
Packit 08bd4c
	int len_avail;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Initialize bit patterns.
Packit 08bd4c
	 */
Packit 08bd4c
	ptn = 0;
Packit 08bd4c
	for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {
Packit 08bd4c
		bitptn[i] = ptn;
Packit 08bd4c
		weight[i] = w;
Packit 08bd4c
		if (hf->freq[i]) {
Packit 08bd4c
			ptn += hf->freq[i] * w;
Packit 08bd4c
			maxbits = i;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	if ((ptn & 0xffff) != 0 || maxbits > hf->tbl_bits)
Packit 08bd4c
		return (0);/* Invalid */
Packit 08bd4c
Packit 08bd4c
	hf->max_bits = maxbits;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Cut out extra bits which we won't house in the table.
Packit 08bd4c
	 * This preparation reduces the same calculation in the for-loop
Packit 08bd4c
	 * making the table.
Packit 08bd4c
	 */
Packit 08bd4c
	if (maxbits < 16) {
Packit 08bd4c
		int ebits = 16 - maxbits;
Packit 08bd4c
		for (i = 1; i <= maxbits; i++) {
Packit 08bd4c
			bitptn[i] >>= ebits;
Packit 08bd4c
			weight[i] >>= ebits;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Make the table.
Packit 08bd4c
	 */
Packit 08bd4c
	tbl_size = 1 << hf->tbl_bits;
Packit 08bd4c
	tbl = hf->tbl;
Packit 08bd4c
	bitlen = hf->bitlen;
Packit 08bd4c
	len_avail = hf->len_size;
Packit 08bd4c
	hf->tree_used = 0;
Packit 08bd4c
	for (i = 0; i < len_avail; i++) {
Packit 08bd4c
		uint16_t *p;
Packit 08bd4c
		int len, cnt;
Packit 08bd4c
Packit 08bd4c
		if (bitlen[i] == 0)
Packit 08bd4c
			continue;
Packit 08bd4c
		/* Get a bit pattern */
Packit 08bd4c
		len = bitlen[i];
Packit 08bd4c
		if (len > tbl_size)
Packit 08bd4c
			return (0);
Packit 08bd4c
		ptn = bitptn[len];
Packit 08bd4c
		cnt = weight[len];
Packit 08bd4c
		/* Calculate next bit pattern */
Packit 08bd4c
		if ((bitptn[len] = ptn + cnt) > tbl_size)
Packit 08bd4c
			return (0);/* Invalid */
Packit 08bd4c
		/* Update the table */
Packit 08bd4c
		p = &(tbl[ptn]);
Packit 08bd4c
		while (--cnt >= 0)
Packit 08bd4c
			p[cnt] = (uint16_t)i;
Packit 08bd4c
	}
Packit 08bd4c
	return (1);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static inline int
Packit 08bd4c
lzx_decode_huffman(struct huffman *hf, unsigned rbits)
Packit 08bd4c
{
Packit 08bd4c
	int c;
Packit 08bd4c
	c = hf->tbl[rbits];
Packit 08bd4c
	if (c < hf->len_size)
Packit 08bd4c
		return (c);
Packit 08bd4c
	return (0);
Packit 08bd4c
}