Blame libarchive/archive_read_support_format_lha.c

Packit 08bd4c
/*-
Packit 08bd4c
 * Copyright (c) 2008-2014 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
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
#define MAXMATCH		256	/* Maximum match length. */
Packit 08bd4c
#define MINMATCH		3	/* Minimum match length. */
Packit 08bd4c
/*
Packit 08bd4c
 * Literal table format:
Packit 08bd4c
 * +0              +256                      +510
Packit 08bd4c
 * +---------------+-------------------------+
Packit 08bd4c
 * | literal code  |       match length      |
Packit 08bd4c
 * |   0 ... 255   |  MINMATCH ... MAXMATCH  |
Packit 08bd4c
 * +---------------+-------------------------+
Packit 08bd4c
 *  <---          LT_BITLEN_SIZE         --->
Packit 08bd4c
 */
Packit 08bd4c
/* Literal table size. */
Packit 08bd4c
#define LT_BITLEN_SIZE		(UCHAR_MAX + 1 + MAXMATCH - MINMATCH + 1)
Packit 08bd4c
/* Position table size.
Packit 08bd4c
 * Note: this used for both position table and pre literal table.*/
Packit 08bd4c
#define PT_BITLEN_SIZE		(3 + 16)
Packit 08bd4c
Packit 08bd4c
struct lzh_dec {
Packit 08bd4c
	/* Decoding status. */
Packit 08bd4c
	int     		 state;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Window to see last 8Ki(lh5),32Ki(lh6),64Ki(lh7) bytes of decoded
Packit 08bd4c
	 * data.
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
Packit 08bd4c
	/*
Packit 08bd4c
	 * Bit stream reader.
Packit 08bd4c
	 */
Packit 08bd4c
	struct lzh_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
	} br;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Huffman coding.
Packit 08bd4c
	 */
Packit 08bd4c
	struct huffman {
Packit 08bd4c
		int		 len_size;
Packit 08bd4c
		int		 len_avail;
Packit 08bd4c
		int		 len_bits;
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
#define HTBL_BITS	10
Packit 08bd4c
		int		 max_bits;
Packit 08bd4c
		int		 shift_bits;
Packit 08bd4c
		int		 tbl_bits;
Packit 08bd4c
		int		 tree_used;
Packit 08bd4c
		int		 tree_avail;
Packit 08bd4c
		/* Direct access table. */
Packit 08bd4c
		uint16_t	*tbl;
Packit 08bd4c
		/* Binary tree table for extra bits over the direct access. */
Packit 08bd4c
		struct htree_t {
Packit 08bd4c
			uint16_t left;
Packit 08bd4c
			uint16_t right;
Packit 08bd4c
		}		*tree;
Packit 08bd4c
	}			 lt, pt;
Packit 08bd4c
Packit 08bd4c
	int			 blocks_avail;
Packit 08bd4c
	int			 pos_pt_len_size;
Packit 08bd4c
	int			 pos_pt_len_bits;
Packit 08bd4c
	int			 literal_pt_len_size;
Packit 08bd4c
	int			 literal_pt_len_bits;
Packit 08bd4c
	int			 reading_position;
Packit 08bd4c
	int			 loop;
Packit 08bd4c
	int			 error;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
struct lzh_stream {
Packit 08bd4c
	const unsigned char	*next_in;
Packit 08bd4c
	int			 avail_in;
Packit 08bd4c
	int64_t			 total_in;
Packit 08bd4c
	const unsigned char	*ref_ptr;
Packit 08bd4c
	int			 avail_out;
Packit 08bd4c
	int64_t			 total_out;
Packit 08bd4c
	struct lzh_dec		*ds;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
struct lha {
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
	uint16_t		 entry_crc_calculated;
Packit 08bd4c
 
Packit 08bd4c
	size_t			 header_size;	/* header size		    */
Packit 08bd4c
	unsigned char		 level;		/* header level		    */
Packit 08bd4c
	char			 method[3];	/* compress type	    */
Packit 08bd4c
	int64_t			 compsize;	/* compressed data size	    */
Packit 08bd4c
	int64_t			 origsize;	/* original file size	    */
Packit 08bd4c
	int			 setflag;
Packit 08bd4c
#define BIRTHTIME_IS_SET	1
Packit 08bd4c
#define ATIME_IS_SET		2
Packit 08bd4c
#define UNIX_MODE_IS_SET	4
Packit 08bd4c
#define CRC_IS_SET		8
Packit 08bd4c
	time_t			 birthtime;
Packit 08bd4c
	long			 birthtime_tv_nsec;
Packit 08bd4c
	time_t			 mtime;
Packit 08bd4c
	long			 mtime_tv_nsec;
Packit 08bd4c
	time_t			 atime;
Packit 08bd4c
	long			 atime_tv_nsec;
Packit 08bd4c
	mode_t			 mode;
Packit 08bd4c
	int64_t			 uid;
Packit 08bd4c
	int64_t			 gid;
Packit 08bd4c
	struct archive_string 	 uname;
Packit 08bd4c
	struct archive_string 	 gname;
Packit 08bd4c
	uint16_t		 header_crc;
Packit 08bd4c
	uint16_t		 crc;
Packit 08bd4c
	struct archive_string_conv *sconv;
Packit 08bd4c
	struct archive_string_conv *opt_sconv;
Packit 08bd4c
Packit 08bd4c
	struct archive_string 	 dirname;
Packit 08bd4c
	struct archive_string 	 filename;
Packit 08bd4c
	struct archive_wstring	 ws;
Packit 08bd4c
Packit 08bd4c
	unsigned char		 dos_attr;
Packit 08bd4c
Packit 08bd4c
	/* Flag to mark progress that an archive was read their first header.*/
Packit 08bd4c
	char			 found_first_header;
Packit 08bd4c
	/* Flag to mark that indicates an empty directory. */
Packit 08bd4c
	char			 directory;
Packit 08bd4c
Packit 08bd4c
	/* Flags to mark progress of decompression. */
Packit 08bd4c
	char			 decompress_init;
Packit 08bd4c
	char			 end_of_entry;
Packit 08bd4c
	char			 end_of_entry_cleanup;
Packit 08bd4c
	char			 entry_is_compressed;
Packit 08bd4c
Packit 08bd4c
	char			 format_name[64];
Packit 08bd4c
Packit 08bd4c
	struct lzh_stream	 strm;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * LHA header common member offset.
Packit 08bd4c
 */
Packit 08bd4c
#define H_METHOD_OFFSET	2	/* Compress type. */
Packit 08bd4c
#define H_ATTR_OFFSET	19	/* DOS attribute. */
Packit 08bd4c
#define H_LEVEL_OFFSET	20	/* Header Level.  */
Packit 08bd4c
#define H_SIZE		22	/* Minimum header size. */
Packit 08bd4c
Packit 08bd4c
static int      archive_read_format_lha_bid(struct archive_read *, int);
Packit 08bd4c
static int      archive_read_format_lha_options(struct archive_read *,
Packit 08bd4c
		    const char *, const char *);
Packit 08bd4c
static int	archive_read_format_lha_read_header(struct archive_read *,
Packit 08bd4c
		    struct archive_entry *);
Packit 08bd4c
static int	archive_read_format_lha_read_data(struct archive_read *,
Packit 08bd4c
		    const void **, size_t *, int64_t *);
Packit 08bd4c
static int	archive_read_format_lha_read_data_skip(struct archive_read *);
Packit 08bd4c
static int	archive_read_format_lha_cleanup(struct archive_read *);
Packit 08bd4c
Packit 08bd4c
static void	lha_replace_path_separator(struct lha *,
Packit 08bd4c
		    struct archive_entry *);
Packit 08bd4c
static int	lha_read_file_header_0(struct archive_read *, struct lha *);
Packit 08bd4c
static int	lha_read_file_header_1(struct archive_read *, struct lha *);
Packit 08bd4c
static int	lha_read_file_header_2(struct archive_read *, struct lha *);
Packit 08bd4c
static int	lha_read_file_header_3(struct archive_read *, struct lha *);
Packit 08bd4c
static int	lha_read_file_extended_header(struct archive_read *,
Packit 08bd4c
		    struct lha *, uint16_t *, int, size_t, size_t *);
Packit 08bd4c
static size_t	lha_check_header_format(const void *);
Packit 08bd4c
static int	lha_skip_sfx(struct archive_read *);
Packit 08bd4c
static time_t	lha_dos_time(const unsigned char *);
Packit 08bd4c
static time_t	lha_win_time(uint64_t, long *);
Packit 08bd4c
static unsigned char	lha_calcsum(unsigned char, const void *,
Packit 08bd4c
		    int, size_t);
Packit 08bd4c
static int	lha_parse_linkname(struct archive_string *,
Packit 08bd4c
		    struct archive_string *);
Packit 08bd4c
static int	lha_read_data_none(struct archive_read *, const void **,
Packit 08bd4c
		    size_t *, int64_t *);
Packit 08bd4c
static int	lha_read_data_lzh(struct archive_read *, const void **,
Packit 08bd4c
		    size_t *, int64_t *);
Packit 08bd4c
static void	lha_crc16_init(void);
Packit 08bd4c
static uint16_t lha_crc16(uint16_t, const void *, size_t);
Packit 08bd4c
static int	lzh_decode_init(struct lzh_stream *, const char *);
Packit 08bd4c
static void	lzh_decode_free(struct lzh_stream *);
Packit 08bd4c
static int	lzh_decode(struct lzh_stream *, int);
Packit 08bd4c
static int	lzh_br_fillup(struct lzh_stream *, struct lzh_br *);
Packit 08bd4c
static int	lzh_huffman_init(struct huffman *, size_t, int);
Packit 08bd4c
static void	lzh_huffman_free(struct huffman *);
Packit 08bd4c
static int	lzh_read_pt_bitlen(struct lzh_stream *, int start, int end);
Packit 08bd4c
static int	lzh_make_fake_table(struct huffman *, uint16_t);
Packit 08bd4c
static int	lzh_make_huffman_table(struct huffman *);
Packit 08bd4c
static inline int lzh_decode_huffman(struct huffman *, unsigned);
Packit 08bd4c
static int	lzh_decode_huffman_tree(struct huffman *, unsigned, int);
Packit 08bd4c
Packit 08bd4c
Packit 08bd4c
int
Packit 08bd4c
archive_read_support_format_lha(struct archive *_a)
Packit 08bd4c
{
Packit 08bd4c
	struct archive_read *a = (struct archive_read *)_a;
Packit 08bd4c
	struct lha *lha;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
Packit 08bd4c
	    ARCHIVE_STATE_NEW, "archive_read_support_format_lha");
Packit 08bd4c
Packit 08bd4c
	lha = (struct lha *)calloc(1, sizeof(*lha));
Packit 08bd4c
	if (lha == NULL) {
Packit 08bd4c
		archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
		    "Can't allocate lha data");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	archive_string_init(&lha->ws);
Packit 08bd4c
Packit 08bd4c
	r = __archive_read_register_format(a,
Packit 08bd4c
	    lha,
Packit 08bd4c
	    "lha",
Packit 08bd4c
	    archive_read_format_lha_bid,
Packit 08bd4c
	    archive_read_format_lha_options,
Packit 08bd4c
	    archive_read_format_lha_read_header,
Packit 08bd4c
	    archive_read_format_lha_read_data,
Packit 08bd4c
	    archive_read_format_lha_read_data_skip,
Packit 08bd4c
	    NULL,
Packit 08bd4c
	    archive_read_format_lha_cleanup,
Packit 08bd4c
	    NULL,
Packit 08bd4c
	    NULL);
Packit 08bd4c
Packit 08bd4c
	if (r != ARCHIVE_OK)
Packit 08bd4c
		free(lha);
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static size_t
Packit 08bd4c
lha_check_header_format(const void *h)
Packit 08bd4c
{
Packit 08bd4c
	const unsigned char *p = h;
Packit 08bd4c
	size_t next_skip_bytes;
Packit 08bd4c
Packit 08bd4c
	switch (p[H_METHOD_OFFSET+3]) {
Packit 08bd4c
	/*
Packit 08bd4c
	 * "-lh0-" ... "-lh7-" "-lhd-"
Packit 08bd4c
	 * "-lzs-" "-lz5-"
Packit 08bd4c
	 */
Packit 08bd4c
	case '0': case '1': case '2': case '3':
Packit 08bd4c
	case '4': case '5': case '6': case '7':
Packit 08bd4c
	case 'd':
Packit 08bd4c
	case 's':
Packit 08bd4c
		next_skip_bytes = 4;
Packit 08bd4c
Packit 08bd4c
		/* b0 == 0 means the end of an LHa archive file.	*/
Packit 08bd4c
		if (p[0] == 0)
Packit 08bd4c
			break;
Packit 08bd4c
		if (p[H_METHOD_OFFSET] != '-' || p[H_METHOD_OFFSET+1] != 'l'
Packit 08bd4c
		    ||  p[H_METHOD_OFFSET+4] != '-')
Packit 08bd4c
			break;
Packit 08bd4c
Packit 08bd4c
		if (p[H_METHOD_OFFSET+2] == 'h') {
Packit 08bd4c
			/* "-lh?-" */
Packit 08bd4c
			if (p[H_METHOD_OFFSET+3] == 's')
Packit 08bd4c
				break;
Packit 08bd4c
			if (p[H_LEVEL_OFFSET] == 0)
Packit 08bd4c
				return (0);
Packit 08bd4c
			if (p[H_LEVEL_OFFSET] <= 3 && p[H_ATTR_OFFSET] == 0x20)
Packit 08bd4c
				return (0);
Packit 08bd4c
		}
Packit 08bd4c
		if (p[H_METHOD_OFFSET+2] == 'z') {
Packit 08bd4c
			/* LArc extensions: -lzs-,-lz4- and -lz5- */
Packit 08bd4c
			if (p[H_LEVEL_OFFSET] != 0)
Packit 08bd4c
				break;
Packit 08bd4c
			if (p[H_METHOD_OFFSET+3] == 's'
Packit 08bd4c
			    || p[H_METHOD_OFFSET+3] == '4'
Packit 08bd4c
			    || p[H_METHOD_OFFSET+3] == '5')
Packit 08bd4c
				return (0);
Packit 08bd4c
		}
Packit 08bd4c
		break;
Packit 08bd4c
	case 'h': next_skip_bytes = 1; break;
Packit 08bd4c
	case 'z': next_skip_bytes = 1; break;
Packit 08bd4c
	case 'l': next_skip_bytes = 2; break;
Packit 08bd4c
	case '-': next_skip_bytes = 3; break;
Packit 08bd4c
	default : next_skip_bytes = 4; break;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	return (next_skip_bytes);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_lha_bid(struct archive_read *a, int best_bid)
Packit 08bd4c
{
Packit 08bd4c
	const char *p;
Packit 08bd4c
	const void *buff;
Packit 08bd4c
	ssize_t bytes_avail, offset, window;
Packit 08bd4c
	size_t next;
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 > 30)
Packit 08bd4c
		return (-1);
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, H_SIZE, NULL)) == NULL)
Packit 08bd4c
		return (-1);
Packit 08bd4c
Packit 08bd4c
	if (lha_check_header_format(p) == 0)
Packit 08bd4c
		return (30);
Packit 08bd4c
Packit 08bd4c
	if (p[0] == 'M' && p[1] == 'Z') {
Packit 08bd4c
		/* PE file */
Packit 08bd4c
		offset = 0;
Packit 08bd4c
		window = 4096;
Packit 08bd4c
		while (offset < (1024 * 20)) {
Packit 08bd4c
			buff = __archive_read_ahead(a, offset + window,
Packit 08bd4c
			    &bytes_avail);
Packit 08bd4c
			if (buff == NULL) {
Packit 08bd4c
				/* Remaining bytes are less than window. */
Packit 08bd4c
				window >>= 1;
Packit 08bd4c
				if (window < (H_SIZE + 3))
Packit 08bd4c
					return (0);
Packit 08bd4c
				continue;
Packit 08bd4c
			}
Packit 08bd4c
			p = (const char *)buff + offset;
Packit 08bd4c
			while (p + H_SIZE < (const char *)buff + bytes_avail) {
Packit 08bd4c
				if ((next = lha_check_header_format(p)) == 0)
Packit 08bd4c
					return (30);
Packit 08bd4c
				p += next;
Packit 08bd4c
			}
Packit 08bd4c
			offset = p - (const char *)buff;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	return (0);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_lha_options(struct archive_read *a,
Packit 08bd4c
    const char *key, const char *val)
Packit 08bd4c
{
Packit 08bd4c
	struct lha *lha;
Packit 08bd4c
	int ret = ARCHIVE_FAILED;
Packit 08bd4c
Packit 08bd4c
	lha = (struct lha *)(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
			    "lha: hdrcharset option needs a character-set name");
Packit 08bd4c
		else {
Packit 08bd4c
			lha->opt_sconv =
Packit 08bd4c
			    archive_string_conversion_from_charset(
Packit 08bd4c
				&a->archive, val, 0);
Packit 08bd4c
			if (lha->opt_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
lha_skip_sfx(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	const void *h;
Packit 08bd4c
	const char *p, *q;
Packit 08bd4c
	size_t next, skip;
Packit 08bd4c
	ssize_t bytes, window;
Packit 08bd4c
Packit 08bd4c
	window = 4096;
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		h = __archive_read_ahead(a, window, &bytes);
Packit 08bd4c
		if (h == NULL) {
Packit 08bd4c
			/* Remaining bytes are less than window. */
Packit 08bd4c
			window >>= 1;
Packit 08bd4c
			if (window < (H_SIZE + 3))
Packit 08bd4c
				goto fatal;
Packit 08bd4c
			continue;
Packit 08bd4c
		}
Packit 08bd4c
		if (bytes < H_SIZE)
Packit 08bd4c
			goto fatal;
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 lha header.
Packit 08bd4c
		 */
Packit 08bd4c
		while (p + H_SIZE < q) {
Packit 08bd4c
			if ((next = lha_check_header_format(p)) == 0) {
Packit 08bd4c
				skip = p - (const char *)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 - (const char *)h;
Packit 08bd4c
		__archive_read_consume(a, skip);
Packit 08bd4c
	}
Packit 08bd4c
fatal:
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Couldn't find out LHa header");
Packit 08bd4c
	return (ARCHIVE_FATAL);
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 LHa header");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_lha_read_header(struct archive_read *a,
Packit 08bd4c
    struct archive_entry *entry)
Packit 08bd4c
{
Packit 08bd4c
	struct archive_string linkname;
Packit 08bd4c
	struct archive_string pathname;
Packit 08bd4c
	struct lha *lha;
Packit 08bd4c
	const unsigned char *p;
Packit 08bd4c
	const char *signature;
Packit 08bd4c
	int err;
Packit 08bd4c
	
Packit 08bd4c
	lha_crc16_init();
Packit 08bd4c
Packit 08bd4c
	a->archive.archive_format = ARCHIVE_FORMAT_LHA;
Packit 08bd4c
	if (a->archive.archive_format_name == NULL)
Packit 08bd4c
		a->archive.archive_format_name = "lha";
Packit 08bd4c
Packit 08bd4c
	lha = (struct lha *)(a->format->data);
Packit 08bd4c
	lha->decompress_init = 0;
Packit 08bd4c
	lha->end_of_entry = 0;
Packit 08bd4c
	lha->end_of_entry_cleanup = 0;
Packit 08bd4c
	lha->entry_unconsumed = 0;
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, H_SIZE, NULL)) == NULL) {
Packit 08bd4c
		/*
Packit 08bd4c
		 * LHa archiver added 0 to the tail of its archive file as
Packit 08bd4c
		 * the mark of the end of the archive.
Packit 08bd4c
		 */
Packit 08bd4c
		signature = __archive_read_ahead(a, sizeof(signature[0]), NULL);
Packit 08bd4c
		if (signature == NULL || signature[0] == 0)
Packit 08bd4c
			return (ARCHIVE_EOF);
Packit 08bd4c
		return (truncated_error(a));
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	signature = (const char *)p;
Packit 08bd4c
	if (lha->found_first_header == 0 &&
Packit 08bd4c
	    signature[0] == 'M' && signature[1] == 'Z') {
Packit 08bd4c
                /* This is an executable?  Must be self-extracting... 	*/
Packit 08bd4c
		err = lha_skip_sfx(a);
Packit 08bd4c
		if (err < ARCHIVE_WARN)
Packit 08bd4c
			return (err);
Packit 08bd4c
Packit 08bd4c
		if ((p = __archive_read_ahead(a, sizeof(*p), NULL)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
		signature = (const char *)p;
Packit 08bd4c
	}
Packit 08bd4c
	/* signature[0] == 0 means the end of an LHa archive file. */
Packit 08bd4c
	if (signature[0] == 0)
Packit 08bd4c
		return (ARCHIVE_EOF);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Check the header format and method type.
Packit 08bd4c
	 */
Packit 08bd4c
	if (lha_check_header_format(p) != 0) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Bad LHa file");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* We've found the first header. */
Packit 08bd4c
	lha->found_first_header = 1;
Packit 08bd4c
	/* Set a default value and common data */
Packit 08bd4c
	lha->header_size = 0;
Packit 08bd4c
	lha->level = p[H_LEVEL_OFFSET];
Packit 08bd4c
	lha->method[0] = p[H_METHOD_OFFSET+1];
Packit 08bd4c
	lha->method[1] = p[H_METHOD_OFFSET+2];
Packit 08bd4c
	lha->method[2] = p[H_METHOD_OFFSET+3];
Packit 08bd4c
	if (memcmp(lha->method, "lhd", 3) == 0)
Packit 08bd4c
		lha->directory = 1;
Packit 08bd4c
	else
Packit 08bd4c
		lha->directory = 0;
Packit 08bd4c
	if (memcmp(lha->method, "lh0", 3) == 0 ||
Packit 08bd4c
	    memcmp(lha->method, "lz4", 3) == 0)
Packit 08bd4c
		lha->entry_is_compressed = 0;
Packit 08bd4c
	else
Packit 08bd4c
		lha->entry_is_compressed = 1;
Packit 08bd4c
Packit 08bd4c
	lha->compsize = 0;
Packit 08bd4c
	lha->origsize = 0;
Packit 08bd4c
	lha->setflag = 0;
Packit 08bd4c
	lha->birthtime = 0;
Packit 08bd4c
	lha->birthtime_tv_nsec = 0;
Packit 08bd4c
	lha->mtime = 0;
Packit 08bd4c
	lha->mtime_tv_nsec = 0;
Packit 08bd4c
	lha->atime = 0;
Packit 08bd4c
	lha->atime_tv_nsec = 0;
Packit 08bd4c
	lha->mode = (lha->directory)? 0777 : 0666;
Packit 08bd4c
	lha->uid = 0;
Packit 08bd4c
	lha->gid = 0;
Packit 08bd4c
	archive_string_empty(&lha->dirname);
Packit 08bd4c
	archive_string_empty(&lha->filename);
Packit 08bd4c
	lha->dos_attr = 0;
Packit 08bd4c
	if (lha->opt_sconv != NULL)
Packit 08bd4c
		lha->sconv = lha->opt_sconv;
Packit 08bd4c
	else
Packit 08bd4c
		lha->sconv = NULL;
Packit 08bd4c
Packit 08bd4c
	switch (p[H_LEVEL_OFFSET]) {
Packit 08bd4c
	case 0:
Packit 08bd4c
		err = lha_read_file_header_0(a, lha);
Packit 08bd4c
		break;
Packit 08bd4c
	case 1:
Packit 08bd4c
		err = lha_read_file_header_1(a, lha);
Packit 08bd4c
		break;
Packit 08bd4c
	case 2:
Packit 08bd4c
		err = lha_read_file_header_2(a, lha);
Packit 08bd4c
		break;
Packit 08bd4c
	case 3:
Packit 08bd4c
		err = lha_read_file_header_3(a, lha);
Packit 08bd4c
		break;
Packit 08bd4c
	default:
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Unsupported LHa header level %d", p[H_LEVEL_OFFSET]);
Packit 08bd4c
		err = ARCHIVE_FATAL;
Packit 08bd4c
		break;
Packit 08bd4c
	}
Packit 08bd4c
	if (err < ARCHIVE_WARN)
Packit 08bd4c
		return (err);
Packit 08bd4c
Packit 08bd4c
Packit 08bd4c
	if (!lha->directory && archive_strlen(&lha->filename) == 0)
Packit 08bd4c
		/* The filename has not been set */
Packit 08bd4c
		return (truncated_error(a));
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Make a pathname from a dirname and a filename.
Packit 08bd4c
	 */
Packit 08bd4c
	archive_string_concat(&lha->dirname, &lha->filename);
Packit 08bd4c
	archive_string_init(&pathname);
Packit 08bd4c
	archive_string_init(&linkname);
Packit 08bd4c
	archive_string_copy(&pathname, &lha->dirname);
Packit 08bd4c
Packit 08bd4c
	if ((lha->mode & AE_IFMT) == AE_IFLNK) {
Packit 08bd4c
		/*
Packit 08bd4c
	 	 * Extract the symlink-name if it's included in the pathname.
Packit 08bd4c
	 	 */
Packit 08bd4c
		if (!lha_parse_linkname(&linkname, &pathname)) {
Packit 08bd4c
			/* We couldn't get the symlink-name. */
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
		    	    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Unknown symlink-name");
Packit 08bd4c
			archive_string_free(&pathname);
Packit 08bd4c
			archive_string_free(&linkname);
Packit 08bd4c
			return (ARCHIVE_FAILED);
Packit 08bd4c
		}
Packit 08bd4c
	} else {
Packit 08bd4c
		/*
Packit 08bd4c
		 * Make sure a file-type is set.
Packit 08bd4c
		 * The mode has been overridden if it is in the extended data.
Packit 08bd4c
		 */
Packit 08bd4c
		lha->mode = (lha->mode & ~AE_IFMT) |
Packit 08bd4c
		    ((lha->directory)? AE_IFDIR: AE_IFREG);
Packit 08bd4c
	}
Packit 08bd4c
	if ((lha->setflag & UNIX_MODE_IS_SET) == 0 &&
Packit 08bd4c
	    (lha->dos_attr & 1) != 0)
Packit 08bd4c
		lha->mode &= ~(0222);/* read only. */
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Set basic file parameters.
Packit 08bd4c
	 */
Packit 08bd4c
	if (archive_entry_copy_pathname_l(entry, pathname.s,
Packit 08bd4c
	    pathname.length, lha->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(lha->sconv));
Packit 08bd4c
		err = ARCHIVE_WARN;
Packit 08bd4c
	}
Packit 08bd4c
	archive_string_free(&pathname);
Packit 08bd4c
	if (archive_strlen(&linkname) > 0) {
Packit 08bd4c
		if (archive_entry_copy_symlink_l(entry, linkname.s,
Packit 08bd4c
		    linkname.length, lha->sconv) != 0) {
Packit 08bd4c
			if (errno == ENOMEM) {
Packit 08bd4c
				archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
				    "Can't allocate memory for Linkname");
Packit 08bd4c
				return (ARCHIVE_FATAL);
Packit 08bd4c
			}
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Linkname cannot be converted "
Packit 08bd4c
			    "from %s to current locale.",
Packit 08bd4c
			    archive_string_conversion_charset_name(lha->sconv));
Packit 08bd4c
			err = ARCHIVE_WARN;
Packit 08bd4c
		}
Packit 08bd4c
	} else
Packit 08bd4c
		archive_entry_set_symlink(entry, NULL);
Packit 08bd4c
	archive_string_free(&linkname);
Packit 08bd4c
	/*
Packit 08bd4c
	 * When a header level is 0, there is a possibility that
Packit 08bd4c
	 * a pathname and a symlink has '\' character, a directory
Packit 08bd4c
	 * separator in DOS/Windows. So we should convert it to '/'.
Packit 08bd4c
	 */
Packit 08bd4c
	if (p[H_LEVEL_OFFSET] == 0)
Packit 08bd4c
		lha_replace_path_separator(lha, entry);
Packit 08bd4c
Packit 08bd4c
	archive_entry_set_mode(entry, lha->mode);
Packit 08bd4c
	archive_entry_set_uid(entry, lha->uid);
Packit 08bd4c
	archive_entry_set_gid(entry, lha->gid);
Packit 08bd4c
	if (archive_strlen(&lha->uname) > 0)
Packit 08bd4c
		archive_entry_set_uname(entry, lha->uname.s);
Packit 08bd4c
	if (archive_strlen(&lha->gname) > 0)
Packit 08bd4c
		archive_entry_set_gname(entry, lha->gname.s);
Packit 08bd4c
	if (lha->setflag & BIRTHTIME_IS_SET) {
Packit 08bd4c
		archive_entry_set_birthtime(entry, lha->birthtime,
Packit 08bd4c
		    lha->birthtime_tv_nsec);
Packit 08bd4c
		archive_entry_set_ctime(entry, lha->birthtime,
Packit 08bd4c
		    lha->birthtime_tv_nsec);
Packit 08bd4c
	} else {
Packit 08bd4c
		archive_entry_unset_birthtime(entry);
Packit 08bd4c
		archive_entry_unset_ctime(entry);
Packit 08bd4c
	}
Packit 08bd4c
	archive_entry_set_mtime(entry, lha->mtime, lha->mtime_tv_nsec);
Packit 08bd4c
	if (lha->setflag & ATIME_IS_SET)
Packit 08bd4c
		archive_entry_set_atime(entry, lha->atime,
Packit 08bd4c
		    lha->atime_tv_nsec);
Packit 08bd4c
	else
Packit 08bd4c
		archive_entry_unset_atime(entry);
Packit 08bd4c
	if (lha->directory || archive_entry_symlink(entry) != NULL)
Packit 08bd4c
		archive_entry_unset_size(entry);
Packit 08bd4c
	else
Packit 08bd4c
		archive_entry_set_size(entry, lha->origsize);
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Prepare variables used to read a file content.
Packit 08bd4c
	 */
Packit 08bd4c
	lha->entry_bytes_remaining = lha->compsize;
Packit 08bd4c
	lha->entry_offset = 0;
Packit 08bd4c
	lha->entry_crc_calculated = 0;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * This file does not have a content.
Packit 08bd4c
	 */
Packit 08bd4c
	if (lha->directory || lha->compsize == 0)
Packit 08bd4c
		lha->end_of_entry = 1;
Packit 08bd4c
Packit 08bd4c
	sprintf(lha->format_name, "lha -%c%c%c-",
Packit 08bd4c
	    lha->method[0], lha->method[1], lha->method[2]);
Packit 08bd4c
	a->archive.archive_format_name = lha->format_name;
Packit 08bd4c
Packit 08bd4c
	return (err);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Replace a DOS path separator '\' by a character '/'.
Packit 08bd4c
 * Some multi-byte character set have  a character '\' in its second byte.
Packit 08bd4c
 */
Packit 08bd4c
static void
Packit 08bd4c
lha_replace_path_separator(struct lha *lha, struct archive_entry *entry)
Packit 08bd4c
{
Packit 08bd4c
	const wchar_t *wp;
Packit 08bd4c
	size_t i;
Packit 08bd4c
Packit 08bd4c
	if ((wp = archive_entry_pathname_w(entry)) != NULL) {
Packit 08bd4c
		archive_wstrcpy(&(lha->ws), wp);
Packit 08bd4c
		for (i = 0; i < archive_strlen(&(lha->ws)); i++) {
Packit 08bd4c
			if (lha->ws.s[i] == L'\\')
Packit 08bd4c
				lha->ws.s[i] = L'/';
Packit 08bd4c
		}
Packit 08bd4c
		archive_entry_copy_pathname_w(entry, lha->ws.s);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if ((wp = archive_entry_symlink_w(entry)) != NULL) {
Packit 08bd4c
		archive_wstrcpy(&(lha->ws), wp);
Packit 08bd4c
		for (i = 0; i < archive_strlen(&(lha->ws)); i++) {
Packit 08bd4c
			if (lha->ws.s[i] == L'\\')
Packit 08bd4c
				lha->ws.s[i] = L'/';
Packit 08bd4c
		}
Packit 08bd4c
		archive_entry_copy_symlink_w(entry, lha->ws.s);
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Header 0 format
Packit 08bd4c
 *
Packit 08bd4c
 * +0              +1         +2               +7                  +11
Packit 08bd4c
 * +---------------+----------+----------------+-------------------+
Packit 08bd4c
 * |header size(*1)|header sum|compression type|compressed size(*2)|
Packit 08bd4c
 * +---------------+----------+----------------+-------------------+
Packit 08bd4c
 *                             <---------------------(*1)----------*
Packit 08bd4c
 *
Packit 08bd4c
 * +11               +15       +17       +19            +20              +21
Packit 08bd4c
 * +-----------------+---------+---------+--------------+----------------+
Packit 08bd4c
 * |uncompressed size|time(DOS)|date(DOS)|attribute(DOS)|header level(=0)|
Packit 08bd4c
 * +-----------------+---------+---------+--------------+----------------+
Packit 08bd4c
 * *--------------------------------(*1)---------------------------------*
Packit 08bd4c
 *
Packit 08bd4c
 * +21             +22       +22+(*3)   +22+(*3)+2       +22+(*3)+2+(*4)
Packit 08bd4c
 * +---------------+---------+----------+----------------+------------------+
Packit 08bd4c
 * |name length(*3)|file name|file CRC16|extra header(*4)|  compressed data |
Packit 08bd4c
 * +---------------+---------+----------+----------------+------------------+
Packit 08bd4c
 *                  <--(*3)->                             <------(*2)------>
Packit 08bd4c
 * *----------------------(*1)-------------------------->
Packit 08bd4c
 *
Packit 08bd4c
 */
Packit 08bd4c
#define H0_HEADER_SIZE_OFFSET	0
Packit 08bd4c
#define H0_HEADER_SUM_OFFSET	1
Packit 08bd4c
#define H0_COMP_SIZE_OFFSET	7
Packit 08bd4c
#define H0_ORIG_SIZE_OFFSET	11
Packit 08bd4c
#define H0_DOS_TIME_OFFSET	15
Packit 08bd4c
#define H0_NAME_LEN_OFFSET	21
Packit 08bd4c
#define H0_FILE_NAME_OFFSET	22
Packit 08bd4c
#define H0_FIXED_SIZE		24
Packit 08bd4c
static int
Packit 08bd4c
lha_read_file_header_0(struct archive_read *a, struct lha *lha)
Packit 08bd4c
{
Packit 08bd4c
	const unsigned char *p;
Packit 08bd4c
	int extdsize, namelen;
Packit 08bd4c
	unsigned char headersum, sum_calculated;
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, H0_FIXED_SIZE, NULL)) == NULL)
Packit 08bd4c
		return (truncated_error(a));
Packit 08bd4c
	lha->header_size = p[H0_HEADER_SIZE_OFFSET] + 2;
Packit 08bd4c
	headersum = p[H0_HEADER_SUM_OFFSET];
Packit 08bd4c
	lha->compsize = archive_le32dec(p + H0_COMP_SIZE_OFFSET);
Packit 08bd4c
	lha->origsize = archive_le32dec(p + H0_ORIG_SIZE_OFFSET);
Packit 08bd4c
	lha->mtime = lha_dos_time(p + H0_DOS_TIME_OFFSET);
Packit 08bd4c
	namelen = p[H0_NAME_LEN_OFFSET];
Packit 08bd4c
	extdsize = (int)lha->header_size - H0_FIXED_SIZE - namelen;
Packit 08bd4c
	if ((namelen > 221 || extdsize < 0) && extdsize != -2) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Invalid LHa header");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL)
Packit 08bd4c
		return (truncated_error(a));
Packit 08bd4c
Packit 08bd4c
	archive_strncpy(&lha->filename, p + H0_FILE_NAME_OFFSET, namelen);
Packit 08bd4c
	/* When extdsize == -2, A CRC16 value is not present in the header. */
Packit 08bd4c
	if (extdsize >= 0) {
Packit 08bd4c
		lha->crc = archive_le16dec(p + H0_FILE_NAME_OFFSET + namelen);
Packit 08bd4c
		lha->setflag |= CRC_IS_SET;
Packit 08bd4c
	}
Packit 08bd4c
	sum_calculated = lha_calcsum(0, p, 2, lha->header_size - 2);
Packit 08bd4c
Packit 08bd4c
	/* Read an extended header */
Packit 08bd4c
	if (extdsize > 0) {
Packit 08bd4c
		/* This extended data is set by 'LHa for UNIX' only.
Packit 08bd4c
		 * Maybe fixed size.
Packit 08bd4c
		 */
Packit 08bd4c
		p += H0_FILE_NAME_OFFSET + namelen + 2;
Packit 08bd4c
		if (p[0] == 'U' && extdsize == 12) {
Packit 08bd4c
			/* p[1] is a minor version. */
Packit 08bd4c
			lha->mtime = archive_le32dec(&p[2]);
Packit 08bd4c
			lha->mode = archive_le16dec(&p[6]);
Packit 08bd4c
			lha->uid = archive_le16dec(&p[8]);
Packit 08bd4c
			lha->gid = archive_le16dec(&p[10]);
Packit 08bd4c
			lha->setflag |= UNIX_MODE_IS_SET;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	__archive_read_consume(a, lha->header_size);
Packit 08bd4c
Packit 08bd4c
	if (sum_calculated != headersum) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
		    "LHa header sum error");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Header 1 format
Packit 08bd4c
 *
Packit 08bd4c
 * +0              +1         +2               +7            +11
Packit 08bd4c
 * +---------------+----------+----------------+-------------+
Packit 08bd4c
 * |header size(*1)|header sum|compression type|skip size(*2)|
Packit 08bd4c
 * +---------------+----------+----------------+-------------+
Packit 08bd4c
 *                             <---------------(*1)----------*
Packit 08bd4c
 *
Packit 08bd4c
 * +11               +15       +17       +19            +20              +21
Packit 08bd4c
 * +-----------------+---------+---------+--------------+----------------+
Packit 08bd4c
 * |uncompressed size|time(DOS)|date(DOS)|attribute(DOS)|header level(=1)|
Packit 08bd4c
 * +-----------------+---------+---------+--------------+----------------+
Packit 08bd4c
 * *-------------------------------(*1)----------------------------------*
Packit 08bd4c
 *
Packit 08bd4c
 * +21             +22       +22+(*3)   +22+(*3)+2  +22+(*3)+3  +22+(*3)+3+(*4)
Packit 08bd4c
 * +---------------+---------+----------+-----------+-----------+
Packit 08bd4c
 * |name length(*3)|file name|file CRC16|  creator  |padding(*4)|
Packit 08bd4c
 * +---------------+---------+----------+-----------+-----------+
Packit 08bd4c
 *                  <--(*3)->
Packit 08bd4c
 * *----------------------------(*1)----------------------------*
Packit 08bd4c
 *
Packit 08bd4c
 * +22+(*3)+3+(*4)  +22+(*3)+3+(*4)+2     +22+(*3)+3+(*4)+2+(*5)
Packit 08bd4c
 * +----------------+---------------------+------------------------+
Packit 08bd4c
 * |next header size| extended header(*5) |     compressed data    |
Packit 08bd4c
 * +----------------+---------------------+------------------------+
Packit 08bd4c
 * *------(*1)-----> <--------------------(*2)-------------------->
Packit 08bd4c
 */
Packit 08bd4c
#define H1_HEADER_SIZE_OFFSET	0
Packit 08bd4c
#define H1_HEADER_SUM_OFFSET	1
Packit 08bd4c
#define H1_COMP_SIZE_OFFSET	7
Packit 08bd4c
#define H1_ORIG_SIZE_OFFSET	11
Packit 08bd4c
#define H1_DOS_TIME_OFFSET	15
Packit 08bd4c
#define H1_NAME_LEN_OFFSET	21
Packit 08bd4c
#define H1_FILE_NAME_OFFSET	22
Packit 08bd4c
#define H1_FIXED_SIZE		27
Packit 08bd4c
static int
Packit 08bd4c
lha_read_file_header_1(struct archive_read *a, struct lha *lha)
Packit 08bd4c
{
Packit 08bd4c
	const unsigned char *p;
Packit 08bd4c
	size_t extdsize;
Packit 08bd4c
	int i, err, err2;
Packit 08bd4c
	int namelen, padding;
Packit 08bd4c
	unsigned char headersum, sum_calculated;
Packit 08bd4c
Packit 08bd4c
	err = ARCHIVE_OK;
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, H1_FIXED_SIZE, NULL)) == NULL)
Packit 08bd4c
		return (truncated_error(a));
Packit 08bd4c
Packit 08bd4c
	lha->header_size = p[H1_HEADER_SIZE_OFFSET] + 2;
Packit 08bd4c
	headersum = p[H1_HEADER_SUM_OFFSET];
Packit 08bd4c
	/* Note: An extended header size is included in a compsize. */
Packit 08bd4c
	lha->compsize = archive_le32dec(p + H1_COMP_SIZE_OFFSET);
Packit 08bd4c
	lha->origsize = archive_le32dec(p + H1_ORIG_SIZE_OFFSET);
Packit 08bd4c
	lha->mtime = lha_dos_time(p + H1_DOS_TIME_OFFSET);
Packit 08bd4c
	namelen = p[H1_NAME_LEN_OFFSET];
Packit 08bd4c
	/* Calculate a padding size. The result will be normally 0 only(?) */
Packit 08bd4c
	padding = ((int)lha->header_size) - H1_FIXED_SIZE - namelen;
Packit 08bd4c
Packit 08bd4c
	if (namelen > 230 || padding < 0)
Packit 08bd4c
		goto invalid;
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL)
Packit 08bd4c
		return (truncated_error(a));
Packit 08bd4c
Packit 08bd4c
	for (i = 0; i < namelen; i++) {
Packit 08bd4c
		if (p[i + H1_FILE_NAME_OFFSET] == 0xff)
Packit 08bd4c
			goto invalid;/* Invalid filename. */
Packit 08bd4c
	}
Packit 08bd4c
	archive_strncpy(&lha->filename, p + H1_FILE_NAME_OFFSET, namelen);
Packit 08bd4c
	lha->crc = archive_le16dec(p + H1_FILE_NAME_OFFSET + namelen);
Packit 08bd4c
	lha->setflag |= CRC_IS_SET;
Packit 08bd4c
Packit 08bd4c
	sum_calculated = lha_calcsum(0, p, 2, lha->header_size - 2);
Packit 08bd4c
	/* Consume used bytes but not include `next header size' data
Packit 08bd4c
	 * since it will be consumed in lha_read_file_extended_header(). */
Packit 08bd4c
	__archive_read_consume(a, lha->header_size - 2);
Packit 08bd4c
Packit 08bd4c
	/* Read extended headers */
Packit 08bd4c
	err2 = lha_read_file_extended_header(a, lha, NULL, 2,
Packit 08bd4c
	    (size_t)(lha->compsize + 2), &extdsize);
Packit 08bd4c
	if (err2 < ARCHIVE_WARN)
Packit 08bd4c
		return (err2);
Packit 08bd4c
	if (err2 < err)
Packit 08bd4c
		err = err2;
Packit 08bd4c
	/* Get a real compressed file size. */
Packit 08bd4c
	lha->compsize -= extdsize - 2;
Packit 08bd4c
Packit 08bd4c
	if (lha->compsize < 0)
Packit 08bd4c
		goto invalid;	/* Invalid compressed file size */
Packit 08bd4c
Packit 08bd4c
	if (sum_calculated != headersum) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
		    "LHa header sum error");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	return (err);
Packit 08bd4c
invalid:
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Invalid LHa header");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Header 2 format
Packit 08bd4c
 *
Packit 08bd4c
 * +0              +2               +7                  +11               +15
Packit 08bd4c
 * +---------------+----------------+-------------------+-----------------+
Packit 08bd4c
 * |header size(*1)|compression type|compressed size(*2)|uncompressed size|
Packit 08bd4c
 * +---------------+----------------+-------------------+-----------------+
Packit 08bd4c
 *  <--------------------------------(*1)---------------------------------*
Packit 08bd4c
 *
Packit 08bd4c
 * +15               +19          +20              +21        +23         +24
Packit 08bd4c
 * +-----------------+------------+----------------+----------+-----------+
Packit 08bd4c
 * |data/time(time_t)| 0x20 fixed |header level(=2)|file CRC16|  creator  |
Packit 08bd4c
 * +-----------------+------------+----------------+----------+-----------+
Packit 08bd4c
 * *---------------------------------(*1)---------------------------------*
Packit 08bd4c
 *
Packit 08bd4c
 * +24              +26                 +26+(*3)      +26+(*3)+(*4)
Packit 08bd4c
 * +----------------+-------------------+-------------+-------------------+
Packit 08bd4c
 * |next header size|extended header(*3)| padding(*4) |  compressed data  |
Packit 08bd4c
 * +----------------+-------------------+-------------+-------------------+
Packit 08bd4c
 * *--------------------------(*1)-------------------> <------(*2)------->
Packit 08bd4c
 *
Packit 08bd4c
 */
Packit 08bd4c
#define H2_HEADER_SIZE_OFFSET	0
Packit 08bd4c
#define H2_COMP_SIZE_OFFSET	7
Packit 08bd4c
#define H2_ORIG_SIZE_OFFSET	11
Packit 08bd4c
#define H2_TIME_OFFSET		15
Packit 08bd4c
#define H2_CRC_OFFSET		21
Packit 08bd4c
#define H2_FIXED_SIZE		24
Packit 08bd4c
static int
Packit 08bd4c
lha_read_file_header_2(struct archive_read *a, struct lha *lha)
Packit 08bd4c
{
Packit 08bd4c
	const unsigned char *p;
Packit 08bd4c
	size_t extdsize;
Packit 08bd4c
	int err, padding;
Packit 08bd4c
	uint16_t header_crc;
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, H2_FIXED_SIZE, NULL)) == NULL)
Packit 08bd4c
		return (truncated_error(a));
Packit 08bd4c
Packit 08bd4c
	lha->header_size =archive_le16dec(p + H2_HEADER_SIZE_OFFSET);
Packit 08bd4c
	lha->compsize = archive_le32dec(p + H2_COMP_SIZE_OFFSET);
Packit 08bd4c
	lha->origsize = archive_le32dec(p + H2_ORIG_SIZE_OFFSET);
Packit 08bd4c
	lha->mtime = archive_le32dec(p + H2_TIME_OFFSET);
Packit 08bd4c
	lha->crc = archive_le16dec(p + H2_CRC_OFFSET);
Packit 08bd4c
	lha->setflag |= CRC_IS_SET;
Packit 08bd4c
Packit 08bd4c
	if (lha->header_size < H2_FIXED_SIZE) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Invalid LHa header size");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	header_crc = lha_crc16(0, p, H2_FIXED_SIZE);
Packit 08bd4c
	__archive_read_consume(a, H2_FIXED_SIZE);
Packit 08bd4c
Packit 08bd4c
	/* Read extended headers */
Packit 08bd4c
	err = lha_read_file_extended_header(a, lha, &header_crc, 2,
Packit 08bd4c
		  lha->header_size - H2_FIXED_SIZE, &extdsize);
Packit 08bd4c
	if (err < ARCHIVE_WARN)
Packit 08bd4c
		return (err);
Packit 08bd4c
Packit 08bd4c
	/* Calculate a padding size. The result will be normally 0 or 1. */
Packit 08bd4c
	padding = (int)lha->header_size - (int)(H2_FIXED_SIZE + extdsize);
Packit 08bd4c
	if (padding > 0) {
Packit 08bd4c
		if ((p = __archive_read_ahead(a, padding, NULL)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
		header_crc = lha_crc16(header_crc, p, padding);
Packit 08bd4c
		__archive_read_consume(a, padding);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (header_crc != lha->header_crc) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "LHa header CRC error");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	return (err);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Header 3 format
Packit 08bd4c
 *
Packit 08bd4c
 * +0           +2               +7                  +11               +15
Packit 08bd4c
 * +------------+----------------+-------------------+-----------------+
Packit 08bd4c
 * | 0x04 fixed |compression type|compressed size(*2)|uncompressed size|
Packit 08bd4c
 * +------------+----------------+-------------------+-----------------+
Packit 08bd4c
 *  <-------------------------------(*1)-------------------------------*
Packit 08bd4c
 *
Packit 08bd4c
 * +15               +19          +20              +21        +23         +24
Packit 08bd4c
 * +-----------------+------------+----------------+----------+-----------+
Packit 08bd4c
 * |date/time(time_t)| 0x20 fixed |header level(=3)|file CRC16|  creator  |
Packit 08bd4c
 * +-----------------+------------+----------------+----------+-----------+
Packit 08bd4c
 * *--------------------------------(*1)----------------------------------*
Packit 08bd4c
 *
Packit 08bd4c
 * +24             +28              +32                 +32+(*3)
Packit 08bd4c
 * +---------------+----------------+-------------------+-----------------+
Packit 08bd4c
 * |header size(*1)|next header size|extended header(*3)| compressed data |
Packit 08bd4c
 * +---------------+----------------+-------------------+-----------------+
Packit 08bd4c
 * *------------------------(*1)-----------------------> <------(*2)----->
Packit 08bd4c
 *
Packit 08bd4c
 */
Packit 08bd4c
#define H3_FIELD_LEN_OFFSET	0
Packit 08bd4c
#define H3_COMP_SIZE_OFFSET	7
Packit 08bd4c
#define H3_ORIG_SIZE_OFFSET	11
Packit 08bd4c
#define H3_TIME_OFFSET		15
Packit 08bd4c
#define H3_CRC_OFFSET		21
Packit 08bd4c
#define H3_HEADER_SIZE_OFFSET	24
Packit 08bd4c
#define H3_FIXED_SIZE		28
Packit 08bd4c
static int
Packit 08bd4c
lha_read_file_header_3(struct archive_read *a, struct lha *lha)
Packit 08bd4c
{
Packit 08bd4c
	const unsigned char *p;
Packit 08bd4c
	size_t extdsize;
Packit 08bd4c
	int err;
Packit 08bd4c
	uint16_t header_crc;
Packit 08bd4c
Packit 08bd4c
	if ((p = __archive_read_ahead(a, H3_FIXED_SIZE, NULL)) == NULL)
Packit 08bd4c
		return (truncated_error(a));
Packit 08bd4c
Packit 08bd4c
	if (archive_le16dec(p + H3_FIELD_LEN_OFFSET) != 4)
Packit 08bd4c
		goto invalid;
Packit 08bd4c
	lha->header_size =archive_le32dec(p + H3_HEADER_SIZE_OFFSET);
Packit 08bd4c
	lha->compsize = archive_le32dec(p + H3_COMP_SIZE_OFFSET);
Packit 08bd4c
	lha->origsize = archive_le32dec(p + H3_ORIG_SIZE_OFFSET);
Packit 08bd4c
	lha->mtime = archive_le32dec(p + H3_TIME_OFFSET);
Packit 08bd4c
	lha->crc = archive_le16dec(p + H3_CRC_OFFSET);
Packit 08bd4c
	lha->setflag |= CRC_IS_SET;
Packit 08bd4c
Packit 08bd4c
	if (lha->header_size < H3_FIXED_SIZE + 4)
Packit 08bd4c
		goto invalid;
Packit 08bd4c
	header_crc = lha_crc16(0, p, H3_FIXED_SIZE);
Packit 08bd4c
	__archive_read_consume(a, H3_FIXED_SIZE);
Packit 08bd4c
Packit 08bd4c
	/* Read extended headers */
Packit 08bd4c
	err = lha_read_file_extended_header(a, lha, &header_crc, 4,
Packit 08bd4c
		  lha->header_size - H3_FIXED_SIZE, &extdsize);
Packit 08bd4c
	if (err < ARCHIVE_WARN)
Packit 08bd4c
		return (err);
Packit 08bd4c
Packit 08bd4c
	if (header_crc != lha->header_crc) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "LHa header CRC error");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	return (err);
Packit 08bd4c
invalid:
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Invalid LHa header");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Extended header format
Packit 08bd4c
 *
Packit 08bd4c
 * +0             +2        +3  -- used in header 1 and 2
Packit 08bd4c
 * +0             +4        +5  -- used in header 3
Packit 08bd4c
 * +--------------+---------+-------------------+--------------+--
Packit 08bd4c
 * |ex-header size|header id|        data       |ex-header size| .......
Packit 08bd4c
 * +--------------+---------+-------------------+--------------+--
Packit 08bd4c
 *  <-------------( ex-header size)------------> <-- next extended header --*
Packit 08bd4c
 *
Packit 08bd4c
 * If the ex-header size is zero, it is the make of the end of extended
Packit 08bd4c
 * headers.
Packit 08bd4c
 *
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
lha_read_file_extended_header(struct archive_read *a, struct lha *lha,
Packit 08bd4c
    uint16_t *crc, int sizefield_length, size_t limitsize, size_t *total_size)
Packit 08bd4c
{
Packit 08bd4c
	const void *h;
Packit 08bd4c
	const unsigned char *extdheader;
Packit 08bd4c
	size_t	extdsize;
Packit 08bd4c
	size_t	datasize;
Packit 08bd4c
	unsigned int i;
Packit 08bd4c
	unsigned char extdtype;
Packit 08bd4c
Packit 08bd4c
#define EXT_HEADER_CRC		0x00		/* Header CRC and information*/
Packit 08bd4c
#define EXT_FILENAME		0x01		/* Filename 		    */
Packit 08bd4c
#define EXT_DIRECTORY		0x02		/* Directory name	    */
Packit 08bd4c
#define EXT_DOS_ATTR		0x40		/* MS-DOS attribute	    */
Packit 08bd4c
#define EXT_TIMESTAMP		0x41		/* Windows time stamp	    */
Packit 08bd4c
#define EXT_FILESIZE		0x42		/* Large file size	    */
Packit 08bd4c
#define EXT_TIMEZONE		0x43		/* Time zone		    */
Packit 08bd4c
#define EXT_UTF16_FILENAME	0x44		/* UTF-16 filename 	    */
Packit 08bd4c
#define EXT_UTF16_DIRECTORY	0x45		/* UTF-16 directory name    */
Packit 08bd4c
#define EXT_CODEPAGE		0x46		/* Codepage		    */
Packit 08bd4c
#define EXT_UNIX_MODE		0x50		/* File permission	    */
Packit 08bd4c
#define EXT_UNIX_GID_UID	0x51		/* gid,uid		    */
Packit 08bd4c
#define EXT_UNIX_GNAME		0x52		/* Group name		    */
Packit 08bd4c
#define EXT_UNIX_UNAME		0x53		/* User name		    */
Packit 08bd4c
#define EXT_UNIX_MTIME		0x54		/* Modified time	    */
Packit 08bd4c
#define EXT_OS2_NEW_ATTR	0x7f		/* new attribute(OS/2 only) */
Packit 08bd4c
#define EXT_NEW_ATTR		0xff		/* new attribute	    */
Packit 08bd4c
Packit 08bd4c
	*total_size = sizefield_length;
Packit 08bd4c
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		/* Read an extended header size. */
Packit 08bd4c
		if ((h =
Packit 08bd4c
		    __archive_read_ahead(a, sizefield_length, NULL)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
		/* Check if the size is the zero indicates the end of the
Packit 08bd4c
		 * extended header. */
Packit 08bd4c
		if (sizefield_length == sizeof(uint16_t))
Packit 08bd4c
			extdsize = archive_le16dec(h);
Packit 08bd4c
		else
Packit 08bd4c
			extdsize = archive_le32dec(h);
Packit 08bd4c
		if (extdsize == 0) {
Packit 08bd4c
			/* End of extended header */
Packit 08bd4c
			if (crc != NULL)
Packit 08bd4c
				*crc = lha_crc16(*crc, h, sizefield_length);
Packit 08bd4c
			__archive_read_consume(a, sizefield_length);
Packit 08bd4c
			return (ARCHIVE_OK);
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		/* Sanity check to the extended header size. */
Packit 08bd4c
		if (((uint64_t)*total_size + extdsize) >
Packit 08bd4c
				    (uint64_t)limitsize ||
Packit 08bd4c
		    extdsize <= (size_t)sizefield_length)
Packit 08bd4c
			goto invalid;
Packit 08bd4c
Packit 08bd4c
		/* Read the extended header. */
Packit 08bd4c
		if ((h = __archive_read_ahead(a, extdsize, NULL)) == NULL)
Packit 08bd4c
			return (truncated_error(a));
Packit 08bd4c
		*total_size += extdsize;
Packit 08bd4c
Packit 08bd4c
		extdheader = (const unsigned char *)h;
Packit 08bd4c
		/* Get the extended header type. */
Packit 08bd4c
		extdtype = extdheader[sizefield_length];
Packit 08bd4c
		/* Calculate an extended data size. */
Packit 08bd4c
		datasize = extdsize - (1 + sizefield_length);
Packit 08bd4c
		/* Skip an extended header size field and type field. */
Packit 08bd4c
		extdheader += sizefield_length + 1;
Packit 08bd4c
Packit 08bd4c
		if (crc != NULL && extdtype != EXT_HEADER_CRC)
Packit 08bd4c
			*crc = lha_crc16(*crc, h, extdsize);
Packit 08bd4c
		switch (extdtype) {
Packit 08bd4c
		case EXT_HEADER_CRC:
Packit 08bd4c
			/* We only use a header CRC. Following data will not
Packit 08bd4c
			 * be used. */
Packit 08bd4c
			if (datasize >= 2) {
Packit 08bd4c
				lha->header_crc = archive_le16dec(extdheader);
Packit 08bd4c
				if (crc != NULL) {
Packit 08bd4c
					static const char zeros[2] = {0, 0};
Packit 08bd4c
					*crc = lha_crc16(*crc, h,
Packit 08bd4c
					    extdsize - datasize);
Packit 08bd4c
					/* CRC value itself as zero */
Packit 08bd4c
					*crc = lha_crc16(*crc, zeros, 2);
Packit 08bd4c
					*crc = lha_crc16(*crc,
Packit 08bd4c
					    extdheader+2, datasize - 2);
Packit 08bd4c
				}
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_FILENAME:
Packit 08bd4c
			if (datasize == 0) {
Packit 08bd4c
				/* maybe directory header */
Packit 08bd4c
				archive_string_empty(&lha->filename);
Packit 08bd4c
				break;
Packit 08bd4c
			}
Packit 08bd4c
			if (extdheader[0] == '\0')
Packit 08bd4c
				goto invalid;
Packit 08bd4c
			archive_strncpy(&lha->filename,
Packit 08bd4c
			    (const char *)extdheader, datasize);
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_DIRECTORY:
Packit 08bd4c
			if (datasize == 0 || extdheader[0] == '\0')
Packit 08bd4c
				/* no directory name data. exit this case. */
Packit 08bd4c
				goto invalid;
Packit 08bd4c
Packit 08bd4c
			archive_strncpy(&lha->dirname,
Packit 08bd4c
		  	    (const char *)extdheader, datasize);
Packit 08bd4c
			/*
Packit 08bd4c
			 * Convert directory delimiter from 0xFF
Packit 08bd4c
			 * to '/' for local system.
Packit 08bd4c
	 		 */
Packit 08bd4c
			for (i = 0; i < lha->dirname.length; i++) {
Packit 08bd4c
				if ((unsigned char)lha->dirname.s[i] == 0xFF)
Packit 08bd4c
					lha->dirname.s[i] = '/';
Packit 08bd4c
			}
Packit 08bd4c
			/* Is last character directory separator? */
Packit 08bd4c
			if (lha->dirname.s[lha->dirname.length-1] != '/')
Packit 08bd4c
				/* invalid directory data */
Packit 08bd4c
				goto invalid;
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_DOS_ATTR:
Packit 08bd4c
			if (datasize == 2)
Packit 08bd4c
				lha->dos_attr = (unsigned char)
Packit 08bd4c
				    (archive_le16dec(extdheader) & 0xff);
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_TIMESTAMP:
Packit 08bd4c
			if (datasize == (sizeof(uint64_t) * 3)) {
Packit 08bd4c
				lha->birthtime = lha_win_time(
Packit 08bd4c
				    archive_le64dec(extdheader),
Packit 08bd4c
				    &lha->birthtime_tv_nsec);
Packit 08bd4c
				extdheader += sizeof(uint64_t);
Packit 08bd4c
				lha->mtime = lha_win_time(
Packit 08bd4c
				    archive_le64dec(extdheader),
Packit 08bd4c
				    &lha->mtime_tv_nsec);
Packit 08bd4c
				extdheader += sizeof(uint64_t);
Packit 08bd4c
				lha->atime = lha_win_time(
Packit 08bd4c
				    archive_le64dec(extdheader),
Packit 08bd4c
				    &lha->atime_tv_nsec);
Packit 08bd4c
				lha->setflag |= BIRTHTIME_IS_SET |
Packit 08bd4c
				    ATIME_IS_SET;
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_FILESIZE:
Packit 08bd4c
			if (datasize == sizeof(uint64_t) * 2) {
Packit 08bd4c
				lha->compsize = archive_le64dec(extdheader);
Packit 08bd4c
				extdheader += sizeof(uint64_t);
Packit 08bd4c
				lha->origsize = archive_le64dec(extdheader);
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_CODEPAGE:
Packit 08bd4c
			/* Get an archived filename charset from codepage.
Packit 08bd4c
			 * This overwrites the charset specified by
Packit 08bd4c
			 * hdrcharset option. */
Packit 08bd4c
			if (datasize == sizeof(uint32_t)) {
Packit 08bd4c
				struct archive_string cp;
Packit 08bd4c
				const char *charset;
Packit 08bd4c
Packit 08bd4c
				archive_string_init(&cp;;
Packit 08bd4c
				switch (archive_le32dec(extdheader)) {
Packit 08bd4c
				case 65001: /* UTF-8 */
Packit 08bd4c
					charset = "UTF-8";
Packit 08bd4c
					break;
Packit 08bd4c
				default:
Packit 08bd4c
					archive_string_sprintf(&cp, "CP%d",
Packit 08bd4c
					    (int)archive_le32dec(extdheader));
Packit 08bd4c
					charset = cp.s;
Packit 08bd4c
					break;
Packit 08bd4c
				}
Packit 08bd4c
				lha->sconv =
Packit 08bd4c
				    archive_string_conversion_from_charset(
Packit 08bd4c
					&(a->archive), charset, 1);
Packit 08bd4c
				archive_string_free(&cp;;
Packit 08bd4c
				if (lha->sconv == NULL)
Packit 08bd4c
					return (ARCHIVE_FATAL);
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_UNIX_MODE:
Packit 08bd4c
			if (datasize == sizeof(uint16_t)) {
Packit 08bd4c
				lha->mode = archive_le16dec(extdheader);
Packit 08bd4c
				lha->setflag |= UNIX_MODE_IS_SET;
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_UNIX_GID_UID:
Packit 08bd4c
			if (datasize == (sizeof(uint16_t) * 2)) {
Packit 08bd4c
				lha->gid = archive_le16dec(extdheader);
Packit 08bd4c
				lha->uid = archive_le16dec(extdheader+2);
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_UNIX_GNAME:
Packit 08bd4c
			if (datasize > 0)
Packit 08bd4c
				archive_strncpy(&lha->gname,
Packit 08bd4c
				    (const char *)extdheader, datasize);
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_UNIX_UNAME:
Packit 08bd4c
			if (datasize > 0)
Packit 08bd4c
				archive_strncpy(&lha->uname,
Packit 08bd4c
				    (const char *)extdheader, datasize);
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_UNIX_MTIME:
Packit 08bd4c
			if (datasize == sizeof(uint32_t))
Packit 08bd4c
				lha->mtime = archive_le32dec(extdheader);
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_OS2_NEW_ATTR:
Packit 08bd4c
			/* This extended header is OS/2 depend. */
Packit 08bd4c
			if (datasize == 16) {
Packit 08bd4c
				lha->dos_attr = (unsigned char)
Packit 08bd4c
				    (archive_le16dec(extdheader) & 0xff);
Packit 08bd4c
				lha->mode = archive_le16dec(extdheader+2);
Packit 08bd4c
				lha->gid = archive_le16dec(extdheader+4);
Packit 08bd4c
				lha->uid = archive_le16dec(extdheader+6);
Packit 08bd4c
				lha->birthtime = archive_le32dec(extdheader+8);
Packit 08bd4c
				lha->atime = archive_le32dec(extdheader+12);
Packit 08bd4c
				lha->setflag |= UNIX_MODE_IS_SET
Packit 08bd4c
				    | BIRTHTIME_IS_SET | ATIME_IS_SET;
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_NEW_ATTR:
Packit 08bd4c
			if (datasize == 20) {
Packit 08bd4c
				lha->mode = (mode_t)archive_le32dec(extdheader);
Packit 08bd4c
				lha->gid = archive_le32dec(extdheader+4);
Packit 08bd4c
				lha->uid = archive_le32dec(extdheader+8);
Packit 08bd4c
				lha->birthtime = archive_le32dec(extdheader+12);
Packit 08bd4c
				lha->atime = archive_le32dec(extdheader+16);
Packit 08bd4c
				lha->setflag |= UNIX_MODE_IS_SET
Packit 08bd4c
				    | BIRTHTIME_IS_SET | ATIME_IS_SET;
Packit 08bd4c
			}
Packit 08bd4c
			break;
Packit 08bd4c
		case EXT_TIMEZONE:		/* Not supported */
Packit 08bd4c
		case EXT_UTF16_FILENAME:	/* Not supported */
Packit 08bd4c
		case EXT_UTF16_DIRECTORY:	/* Not supported */
Packit 08bd4c
		default:
Packit 08bd4c
			break;
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		__archive_read_consume(a, extdsize);
Packit 08bd4c
	}
Packit 08bd4c
invalid:
Packit 08bd4c
	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
	    "Invalid extended LHa header");
Packit 08bd4c
	return (ARCHIVE_FATAL);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
lha_end_of_entry(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct lha *lha = (struct lha *)(a->format->data);
Packit 08bd4c
	int r = ARCHIVE_EOF;
Packit 08bd4c
Packit 08bd4c
	if (!lha->end_of_entry_cleanup) {
Packit 08bd4c
		if ((lha->setflag & CRC_IS_SET) &&
Packit 08bd4c
		    lha->crc != lha->entry_crc_calculated) {
Packit 08bd4c
			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
			    "LHa data CRC error");
Packit 08bd4c
			r = ARCHIVE_WARN;
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		/* End-of-entry cleanup done. */
Packit 08bd4c
		lha->end_of_entry_cleanup = 1;
Packit 08bd4c
	}
Packit 08bd4c
	return (r);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_lha_read_data(struct archive_read *a,
Packit 08bd4c
    const void **buff, size_t *size, int64_t *offset)
Packit 08bd4c
{
Packit 08bd4c
	struct lha *lha = (struct lha *)(a->format->data);
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	if (lha->entry_unconsumed) {
Packit 08bd4c
		/* Consume as much as the decompressor actually used. */
Packit 08bd4c
		__archive_read_consume(a, lha->entry_unconsumed);
Packit 08bd4c
		lha->entry_unconsumed = 0;
Packit 08bd4c
	}
Packit 08bd4c
	if (lha->end_of_entry) {
Packit 08bd4c
		*offset = lha->entry_offset;
Packit 08bd4c
		*size = 0;
Packit 08bd4c
		*buff = NULL;
Packit 08bd4c
		return (lha_end_of_entry(a));
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	if (lha->entry_is_compressed)
Packit 08bd4c
		r =  lha_read_data_lzh(a, buff, size, offset);
Packit 08bd4c
	else
Packit 08bd4c
		/* No compression. */
Packit 08bd4c
		r =  lha_read_data_none(a, buff, size, offset);
Packit 08bd4c
	return (r);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Read a file content in no compression.
Packit 08bd4c
 *
Packit 08bd4c
 * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
Packit 08bd4c
 * lha->end_of_entry if it consumes all of the data.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
lha_read_data_none(struct archive_read *a, const void **buff,
Packit 08bd4c
    size_t *size, int64_t *offset)
Packit 08bd4c
{
Packit 08bd4c
	struct lha *lha = (struct lha *)(a->format->data);
Packit 08bd4c
	ssize_t bytes_avail;
Packit 08bd4c
Packit 08bd4c
	if (lha->entry_bytes_remaining == 0) {
Packit 08bd4c
		*buff = NULL;
Packit 08bd4c
		*size = 0;
Packit 08bd4c
		*offset = lha->entry_offset;
Packit 08bd4c
		lha->end_of_entry = 1;
Packit 08bd4c
		return (ARCHIVE_OK);
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
	*buff = __archive_read_ahead(a, 1, &bytes_avail);
Packit 08bd4c
	if (bytes_avail <= 0) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Truncated LHa file data");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	if (bytes_avail > lha->entry_bytes_remaining)
Packit 08bd4c
		bytes_avail = (ssize_t)lha->entry_bytes_remaining;
Packit 08bd4c
	lha->entry_crc_calculated =
Packit 08bd4c
	    lha_crc16(lha->entry_crc_calculated, *buff, bytes_avail);
Packit 08bd4c
	*size = bytes_avail;
Packit 08bd4c
	*offset = lha->entry_offset;
Packit 08bd4c
	lha->entry_offset += bytes_avail;
Packit 08bd4c
	lha->entry_bytes_remaining -= bytes_avail;
Packit 08bd4c
	if (lha->entry_bytes_remaining == 0)
Packit 08bd4c
		lha->end_of_entry = 1;
Packit 08bd4c
	lha->entry_unconsumed = bytes_avail;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Read a file content in LZHUFF encoding.
Packit 08bd4c
 *
Packit 08bd4c
 * Returns ARCHIVE_OK if successful, returns ARCHIVE_WARN if compression is
Packit 08bd4c
 * unsupported, ARCHIVE_FATAL otherwise, sets lha->end_of_entry if it consumes
Packit 08bd4c
 * all of the data.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
lha_read_data_lzh(struct archive_read *a, const void **buff,
Packit 08bd4c
    size_t *size, int64_t *offset)
Packit 08bd4c
{
Packit 08bd4c
	struct lha *lha = (struct lha *)(a->format->data);
Packit 08bd4c
	ssize_t bytes_avail;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
	/* If we haven't yet read any data, initialize the decompressor. */
Packit 08bd4c
	if (!lha->decompress_init) {
Packit 08bd4c
		r = lzh_decode_init(&(lha->strm), lha->method);
Packit 08bd4c
		switch (r) {
Packit 08bd4c
		case ARCHIVE_OK:
Packit 08bd4c
			break;
Packit 08bd4c
		case ARCHIVE_FAILED:
Packit 08bd4c
        		/* Unsupported compression. */
Packit 08bd4c
			*buff = NULL;
Packit 08bd4c
			*size = 0;
Packit 08bd4c
			*offset = 0;
Packit 08bd4c
			archive_set_error(&a->archive,
Packit 08bd4c
			    ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
			    "Unsupported lzh compression method -%c%c%c-",
Packit 08bd4c
			    lha->method[0], lha->method[1], lha->method[2]);
Packit 08bd4c
			/* We know compressed size; just skip it. */
Packit 08bd4c
			archive_read_format_lha_read_data_skip(a);
Packit 08bd4c
			return (ARCHIVE_WARN);
Packit 08bd4c
		default:
Packit 08bd4c
			archive_set_error(&a->archive, ENOMEM,
Packit 08bd4c
			    "Couldn't allocate memory "
Packit 08bd4c
			    "for lzh decompression");
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
		}
Packit 08bd4c
		/* We've initialized decompression for this stream. */
Packit 08bd4c
		lha->decompress_init = 1;
Packit 08bd4c
		lha->strm.avail_out = 0;
Packit 08bd4c
		lha->strm.total_out = 0;
Packit 08bd4c
	}
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
	lha->strm.next_in = __archive_read_ahead(a, 1, &bytes_avail);
Packit 08bd4c
	if (bytes_avail <= 0) {
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
Packit 08bd4c
		    "Truncated LHa file body");
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	if (bytes_avail > lha->entry_bytes_remaining)
Packit 08bd4c
		bytes_avail = (ssize_t)lha->entry_bytes_remaining;
Packit 08bd4c
Packit 08bd4c
	lha->strm.avail_in = (int)bytes_avail;
Packit 08bd4c
	lha->strm.total_in = 0;
Packit 08bd4c
	lha->strm.avail_out = 0;
Packit 08bd4c
Packit 08bd4c
	r = lzh_decode(&(lha->strm), bytes_avail == lha->entry_bytes_remaining);
Packit 08bd4c
	switch (r) {
Packit 08bd4c
	case ARCHIVE_OK:
Packit 08bd4c
		break;
Packit 08bd4c
	case ARCHIVE_EOF:
Packit 08bd4c
		lha->end_of_entry = 1;
Packit 08bd4c
		break;
Packit 08bd4c
	default:
Packit 08bd4c
		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
Packit 08bd4c
		    "Bad lzh data");
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
	}
Packit 08bd4c
	lha->entry_unconsumed = lha->strm.total_in;
Packit 08bd4c
	lha->entry_bytes_remaining -= lha->strm.total_in;
Packit 08bd4c
Packit 08bd4c
	if (lha->strm.avail_out) {
Packit 08bd4c
		*offset = lha->entry_offset;
Packit 08bd4c
		*size = lha->strm.avail_out;
Packit 08bd4c
		*buff = lha->strm.ref_ptr;
Packit 08bd4c
		lha->entry_crc_calculated =
Packit 08bd4c
		    lha_crc16(lha->entry_crc_calculated, *buff, *size);
Packit 08bd4c
		lha->entry_offset += *size;
Packit 08bd4c
	} else {
Packit 08bd4c
		*offset = lha->entry_offset;
Packit 08bd4c
		*size = 0;
Packit 08bd4c
		*buff = NULL;
Packit 08bd4c
		if (lha->end_of_entry)
Packit 08bd4c
			return (lha_end_of_entry(a));
Packit 08bd4c
	}
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Skip a file content.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_lha_read_data_skip(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct lha *lha;
Packit 08bd4c
	int64_t bytes_skipped;
Packit 08bd4c
Packit 08bd4c
	lha = (struct lha *)(a->format->data);
Packit 08bd4c
Packit 08bd4c
	if (lha->entry_unconsumed) {
Packit 08bd4c
		/* Consume as much as the decompressor actually used. */
Packit 08bd4c
		__archive_read_consume(a, lha->entry_unconsumed);
Packit 08bd4c
		lha->entry_unconsumed = 0;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* if we've already read to end of data, we're done. */
Packit 08bd4c
	if (lha->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 = __archive_read_consume(a, lha->entry_bytes_remaining);
Packit 08bd4c
	if (bytes_skipped < 0)
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
Packit 08bd4c
	/* This entry is finished and done. */
Packit 08bd4c
	lha->end_of_entry_cleanup = lha->end_of_entry = 1;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
archive_read_format_lha_cleanup(struct archive_read *a)
Packit 08bd4c
{
Packit 08bd4c
	struct lha *lha = (struct lha *)(a->format->data);
Packit 08bd4c
Packit 08bd4c
	lzh_decode_free(&(lha->strm));
Packit 08bd4c
	archive_string_free(&(lha->dirname));
Packit 08bd4c
	archive_string_free(&(lha->filename));
Packit 08bd4c
	archive_string_free(&(lha->uname));
Packit 08bd4c
	archive_string_free(&(lha->gname));
Packit 08bd4c
	archive_wstring_free(&(lha->ws));
Packit 08bd4c
	free(lha);
Packit 08bd4c
	(a->format->data) = NULL;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * 'LHa for UNIX' utility has archived a symbolic-link name after
Packit 08bd4c
 * a pathname with '|' character.
Packit 08bd4c
 * This function extracts the symbolic-link name from the pathname.
Packit 08bd4c
 *
Packit 08bd4c
 * example.
Packit 08bd4c
 *   1. a symbolic-name is 'aaa/bb/cc'
Packit 08bd4c
 *   2. a filename is 'xxx/bbb'
Packit 08bd4c
 *  then a archived pathname is 'xxx/bbb|aaa/bb/cc'
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
lha_parse_linkname(struct archive_string *linkname,
Packit 08bd4c
    struct archive_string *pathname)
Packit 08bd4c
{
Packit 08bd4c
	char *	linkptr;
Packit 08bd4c
	size_t 	symlen;
Packit 08bd4c
Packit 08bd4c
	linkptr = strchr(pathname->s, '|');
Packit 08bd4c
	if (linkptr != NULL) {
Packit 08bd4c
		symlen = strlen(linkptr + 1);
Packit 08bd4c
		archive_strncpy(linkname, linkptr+1, symlen);
Packit 08bd4c
Packit 08bd4c
		*linkptr = 0;
Packit 08bd4c
		pathname->length = strlen(pathname->s);
Packit 08bd4c
Packit 08bd4c
		return (1);
Packit 08bd4c
	}
Packit 08bd4c
	return (0);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* Convert an MSDOS-style date/time into Unix-style time. */
Packit 08bd4c
static time_t
Packit 08bd4c
lha_dos_time(const unsigned char *p)
Packit 08bd4c
{
Packit 08bd4c
	int msTime, msDate;
Packit 08bd4c
	struct tm ts;
Packit 08bd4c
Packit 08bd4c
	msTime = archive_le16dec(p);
Packit 08bd4c
	msDate = 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
/* Convert an MS-Windows-style date/time into Unix-style time. */
Packit 08bd4c
static time_t
Packit 08bd4c
lha_win_time(uint64_t wintime, long *ns)
Packit 08bd4c
{
Packit 08bd4c
#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
Packit 08bd4c
Packit 08bd4c
	if (wintime >= EPOC_TIME) {
Packit 08bd4c
		wintime -= EPOC_TIME;	/* 1970-01-01 00:00:00 (UTC) */
Packit 08bd4c
		if (ns != NULL)
Packit 08bd4c
			*ns = (long)(wintime % 10000000) * 100;
Packit 08bd4c
		return (wintime / 10000000);
Packit 08bd4c
	} else {
Packit 08bd4c
		if (ns != NULL)
Packit 08bd4c
			*ns = 0;
Packit 08bd4c
		return (0);
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static unsigned char
Packit 08bd4c
lha_calcsum(unsigned char sum, const void *pp, int offset, size_t size)
Packit 08bd4c
{
Packit 08bd4c
	unsigned char const *p = (unsigned char const *)pp;
Packit 08bd4c
Packit 08bd4c
	p += offset;
Packit 08bd4c
	for (;size > 0; --size)
Packit 08bd4c
		sum += *p++;
Packit 08bd4c
	return (sum);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static uint16_t crc16tbl[2][256];
Packit 08bd4c
static void
Packit 08bd4c
lha_crc16_init(void)
Packit 08bd4c
{
Packit 08bd4c
	unsigned int i;
Packit 08bd4c
	static int crc16init = 0;
Packit 08bd4c
Packit 08bd4c
	if (crc16init)
Packit 08bd4c
		return;
Packit 08bd4c
	crc16init = 1;
Packit 08bd4c
Packit 08bd4c
	for (i = 0; i < 256; i++) {
Packit 08bd4c
		unsigned int j;
Packit 08bd4c
		uint16_t crc = (uint16_t)i;
Packit 08bd4c
		for (j = 8; j; j--)
Packit 08bd4c
			crc = (crc >> 1) ^ ((crc & 1) * 0xA001);
Packit 08bd4c
		crc16tbl[0][i] = crc;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	for (i = 0; i < 256; i++) {
Packit 08bd4c
		crc16tbl[1][i] = (crc16tbl[0][i] >> 8)
Packit 08bd4c
			^ crc16tbl[0][crc16tbl[0][i] & 0xff];
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static uint16_t
Packit 08bd4c
lha_crc16(uint16_t crc, const void *pp, size_t len)
Packit 08bd4c
{
Packit 08bd4c
	const unsigned char *p = (const unsigned char *)pp;
Packit 08bd4c
	const uint16_t *buff;
Packit 08bd4c
	const union {
Packit 08bd4c
		uint32_t i;
Packit 08bd4c
		char c[4];
Packit 08bd4c
	} u = { 0x01020304 };
Packit 08bd4c
Packit 08bd4c
	if (len == 0)
Packit 08bd4c
		return crc;
Packit 08bd4c
Packit 08bd4c
	/* Process unaligned address. */
Packit 08bd4c
	if (((uintptr_t)p) & (uintptr_t)0x1) {
Packit 08bd4c
		crc = (crc >> 8) ^ crc16tbl[0][(crc ^ *p++) & 0xff];
Packit 08bd4c
		len--;
Packit 08bd4c
	}
Packit 08bd4c
	buff = (const uint16_t *)p;
Packit 08bd4c
	/*
Packit 08bd4c
	 * Modern C compiler such as GCC does not unroll automatically yet
Packit 08bd4c
	 * without unrolling pragma, and Clang is so. So we should
Packit 08bd4c
	 * unroll this loop for its performance.
Packit 08bd4c
	 */
Packit 08bd4c
	for (;len >= 8; len -= 8) {
Packit 08bd4c
		/* This if statement expects compiler optimization will
Packit 08bd4c
		 * remove the statement which will not be executed. */
Packit 08bd4c
#undef bswap16
Packit 08bd4c
#if defined(_MSC_VER) && _MSC_VER >= 1400  /* Visual Studio */
Packit 08bd4c
#  define bswap16(x) _byteswap_ushort(x)
Packit 08bd4c
#elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ > 4)
Packit 08bd4c
/* GCC 4.8 and later has __builtin_bswap16() */
Packit 08bd4c
#  define bswap16(x) __builtin_bswap16(x)
Packit 08bd4c
#elif defined(__clang__)
Packit 08bd4c
/* All clang versions have __builtin_bswap16() */
Packit 08bd4c
#  define bswap16(x) __builtin_bswap16(x)
Packit 08bd4c
#else
Packit 08bd4c
#  define bswap16(x) ((((x) >> 8) & 0xff) | ((x) << 8))
Packit 08bd4c
#endif
Packit 08bd4c
#define CRC16W	do { 	\
Packit 08bd4c
		if(u.c[0] == 1) { /* Big endian */		\
Packit 08bd4c
			crc ^= bswap16(*buff); buff++;		\
Packit 08bd4c
		} else						\
Packit 08bd4c
			crc ^= *buff++;				\
Packit 08bd4c
		crc = crc16tbl[1][crc & 0xff] ^ crc16tbl[0][crc >> 8];\
Packit 08bd4c
} while (0)
Packit 08bd4c
		CRC16W;
Packit 08bd4c
		CRC16W;
Packit 08bd4c
		CRC16W;
Packit 08bd4c
		CRC16W;
Packit 08bd4c
#undef CRC16W
Packit 08bd4c
#undef bswap16
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	p = (const unsigned char *)buff;
Packit 08bd4c
	for (;len; len--) {
Packit 08bd4c
		crc = (crc >> 8) ^ crc16tbl[0][(crc ^ *p++) & 0xff];
Packit 08bd4c
	}
Packit 08bd4c
	return crc;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Initialize LZHUF decoder.
Packit 08bd4c
 *
Packit 08bd4c
 * Returns ARCHIVE_OK if initialization was successful.
Packit 08bd4c
 * Returns ARCHIVE_FAILED if method is unsupported.
Packit 08bd4c
 * Returns ARCHIVE_FATAL if initialization failed; memory allocation
Packit 08bd4c
 * error occurred.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
lzh_decode_init(struct lzh_stream *strm, const char *method)
Packit 08bd4c
{
Packit 08bd4c
	struct lzh_dec *ds;
Packit 08bd4c
	int w_bits, w_size;
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
	if (method == NULL || method[0] != 'l' || method[1] != 'h')
Packit 08bd4c
		return (ARCHIVE_FAILED);
Packit 08bd4c
	switch (method[2]) {
Packit 08bd4c
	case '5':
Packit 08bd4c
		w_bits = 13;/* 8KiB for window */
Packit 08bd4c
		break;
Packit 08bd4c
	case '6':
Packit 08bd4c
		w_bits = 15;/* 32KiB for window */
Packit 08bd4c
		break;
Packit 08bd4c
	case '7':
Packit 08bd4c
		w_bits = 16;/* 64KiB for window */
Packit 08bd4c
		break;
Packit 08bd4c
	default:
Packit 08bd4c
		return (ARCHIVE_FAILED);/* Not supported. */
Packit 08bd4c
	}
Packit 08bd4c
	ds->error = ARCHIVE_FATAL;
Packit 08bd4c
	/* Expand a window size up to 128 KiB for decompressing process
Packit 08bd4c
	 * performance whatever its original window size is. */
Packit 08bd4c
	ds->w_size = 1U << 17;
Packit 08bd4c
	ds->w_mask = ds->w_size -1;
Packit 08bd4c
	if (ds->w_buff == NULL) {
Packit 08bd4c
		ds->w_buff = malloc(ds->w_size);
Packit 08bd4c
		if (ds->w_buff == NULL)
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	w_size = 1U << w_bits;
Packit 08bd4c
	memset(ds->w_buff + ds->w_size - w_size, 0x20, w_size);
Packit 08bd4c
	ds->w_pos = 0;
Packit 08bd4c
	ds->state = 0;
Packit 08bd4c
	ds->pos_pt_len_size = w_bits + 1;
Packit 08bd4c
	ds->pos_pt_len_bits = (w_bits == 15 || w_bits == 16)? 5: 4;
Packit 08bd4c
	ds->literal_pt_len_size = PT_BITLEN_SIZE;
Packit 08bd4c
	ds->literal_pt_len_bits = 5;
Packit 08bd4c
	ds->br.cache_buffer = 0;
Packit 08bd4c
	ds->br.cache_avail = 0;
Packit 08bd4c
Packit 08bd4c
	if (lzh_huffman_init(&(ds->lt), LT_BITLEN_SIZE, 16)
Packit 08bd4c
	    != ARCHIVE_OK)
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	ds->lt.len_bits = 9;
Packit 08bd4c
	if (lzh_huffman_init(&(ds->pt), PT_BITLEN_SIZE, 16)
Packit 08bd4c
	    != ARCHIVE_OK)
Packit 08bd4c
		return (ARCHIVE_FATAL);
Packit 08bd4c
	ds->error = 0;
Packit 08bd4c
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Release LZHUF decoder.
Packit 08bd4c
 */
Packit 08bd4c
static void
Packit 08bd4c
lzh_decode_free(struct lzh_stream *strm)
Packit 08bd4c
{
Packit 08bd4c
Packit 08bd4c
	if (strm->ds == NULL)
Packit 08bd4c
		return;
Packit 08bd4c
	free(strm->ds->w_buff);
Packit 08bd4c
	lzh_huffman_free(&(strm->ds->lt));
Packit 08bd4c
	lzh_huffman_free(&(strm->ds->pt));
Packit 08bd4c
	free(strm->ds);
Packit 08bd4c
	strm->ds = NULL;
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 lzh_br_has(br, n)	((br)->cache_avail >= n)
Packit 08bd4c
/* Get compressed data by bit. */
Packit 08bd4c
#define lzh_br_bits(br, n)				\
Packit 08bd4c
	(((uint16_t)((br)->cache_buffer >>		\
Packit 08bd4c
		((br)->cache_avail - (n)))) & cache_masks[n])
Packit 08bd4c
#define lzh_br_bits_forced(br, n)			\
Packit 08bd4c
	(((uint16_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 lzh_br_read_ahead_0(strm, br, n)	\
Packit 08bd4c
	(lzh_br_has(br, (n)) || lzh_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 lzh_br_read_ahead(strm, br, n)	\
Packit 08bd4c
	(lzh_br_read_ahead_0((strm), (br), (n)) || lzh_br_has((br), (n)))
Packit 08bd4c
Packit 08bd4c
/* Notify how many bits we consumed. */
Packit 08bd4c
#define lzh_br_consume(br, n)	((br)->cache_avail -= (n))
Packit 08bd4c
#define lzh_br_unconsume(br, n)	((br)->cache_avail += (n))
Packit 08bd4c
Packit 08bd4c
static const uint16_t cache_masks[] = {
Packit 08bd4c
	0x0000, 0x0001, 0x0003, 0x0007,
Packit 08bd4c
	0x000F, 0x001F, 0x003F, 0x007F,
Packit 08bd4c
	0x00FF, 0x01FF, 0x03FF, 0x07FF,
Packit 08bd4c
	0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF,
Packit 08bd4c
	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
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
lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br)
Packit 08bd4c
{
Packit 08bd4c
	int n = CACHE_BITS - br->cache_avail;
Packit 08bd4c
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		const int x = n >> 3;
Packit 08bd4c
		if (strm->avail_in >= x) {
Packit 08bd4c
			switch (x) {
Packit 08bd4c
			case 8:
Packit 08bd4c
				br->cache_buffer =
Packit 08bd4c
				    ((uint64_t)strm->next_in[0]) << 56 |
Packit 08bd4c
				    ((uint64_t)strm->next_in[1]) << 48 |
Packit 08bd4c
				    ((uint64_t)strm->next_in[2]) << 40 |
Packit 08bd4c
				    ((uint64_t)strm->next_in[3]) << 32 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[4]) << 24 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[5]) << 16 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[6]) << 8 |
Packit 08bd4c
				     (uint32_t)strm->next_in[7];
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
			case 7:
Packit 08bd4c
				br->cache_buffer =
Packit 08bd4c
		 		   (br->cache_buffer << 56) |
Packit 08bd4c
				    ((uint64_t)strm->next_in[0]) << 48 |
Packit 08bd4c
				    ((uint64_t)strm->next_in[1]) << 40 |
Packit 08bd4c
				    ((uint64_t)strm->next_in[2]) << 32 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[3]) << 24 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[4]) << 16 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[5]) << 8 |
Packit 08bd4c
				     (uint32_t)strm->next_in[6];
Packit 08bd4c
				strm->next_in += 7;
Packit 08bd4c
				strm->avail_in -= 7;
Packit 08bd4c
				br->cache_avail += 7 * 8;
Packit 08bd4c
				return (1);
Packit 08bd4c
			case 6:
Packit 08bd4c
				br->cache_buffer =
Packit 08bd4c
		 		   (br->cache_buffer << 48) |
Packit 08bd4c
				    ((uint64_t)strm->next_in[0]) << 40 |
Packit 08bd4c
				    ((uint64_t)strm->next_in[1]) << 32 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[2]) << 24 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[3]) << 16 |
Packit 08bd4c
				    ((uint32_t)strm->next_in[4]) << 8 |
Packit 08bd4c
				     (uint32_t)strm->next_in[5];
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
			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
		}
Packit 08bd4c
		if (strm->avail_in == 0) {
Packit 08bd4c
			/* There is not enough compressed data to fill up the
Packit 08bd4c
			 * cache buffer. */
Packit 08bd4c
			return (0);
Packit 08bd4c
		}
Packit 08bd4c
		br->cache_buffer =
Packit 08bd4c
		   (br->cache_buffer << 8) | *strm->next_in++;
Packit 08bd4c
		strm->avail_in--;
Packit 08bd4c
		br->cache_avail += 8;
Packit 08bd4c
		n -= 8;
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Decode LZHUF.
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
 * 4. 'last' flag is very important, you must set 1 to the flag if there
Packit 08bd4c
 *    is no input data. The lha compressed data format does not provide how
Packit 08bd4c
 *    to know the compressed data is really finished.
Packit 08bd4c
 *    Note: lha command utility check if the total size of output bytes is
Packit 08bd4c
 *    reached the uncompressed size recorded in its header. it does not mind
Packit 08bd4c
 *    that the decoding process is properly finished.
Packit 08bd4c
 *    GNU ZIP can decompress another compressed file made by SCO LZH compress.
Packit 08bd4c
 *    it handles EOF as null to fill read buffer with zero until the decoding
Packit 08bd4c
 *    process meet 2 bytes of zeros at reading a size of a next chunk, so the
Packit 08bd4c
 *    zeros are treated as the mark of the end of the data although the zeros
Packit 08bd4c
 *    is dummy, not the file data.
Packit 08bd4c
 */
Packit 08bd4c
static int	lzh_read_blocks(struct lzh_stream *, int);
Packit 08bd4c
static int	lzh_decode_blocks(struct lzh_stream *, int);
Packit 08bd4c
#define ST_RD_BLOCK		0
Packit 08bd4c
#define ST_RD_PT_1		1
Packit 08bd4c
#define ST_RD_PT_2		2
Packit 08bd4c
#define ST_RD_PT_3		3
Packit 08bd4c
#define ST_RD_PT_4		4
Packit 08bd4c
#define ST_RD_LITERAL_1		5
Packit 08bd4c
#define ST_RD_LITERAL_2		6
Packit 08bd4c
#define ST_RD_LITERAL_3		7
Packit 08bd4c
#define ST_RD_POS_DATA_1	8
Packit 08bd4c
#define ST_GET_LITERAL		9
Packit 08bd4c
#define ST_GET_POS_1		10
Packit 08bd4c
#define ST_GET_POS_2		11
Packit 08bd4c
#define ST_COPY_DATA		12
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
lzh_decode(struct lzh_stream *strm, int last)
Packit 08bd4c
{
Packit 08bd4c
	struct lzh_dec *ds = strm->ds;
Packit 08bd4c
	int 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
	do {
Packit 08bd4c
		if (ds->state < ST_GET_LITERAL)
Packit 08bd4c
			r = lzh_read_blocks(strm, last);
Packit 08bd4c
		else
Packit 08bd4c
			r = lzh_decode_blocks(strm, last);
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 void
Packit 08bd4c
lzh_emit_window(struct lzh_stream *strm, size_t s)
Packit 08bd4c
{
Packit 08bd4c
	strm->ref_ptr = strm->ds->w_buff;
Packit 08bd4c
	strm->avail_out = (int)s;
Packit 08bd4c
	strm->total_out += s;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
lzh_read_blocks(struct lzh_stream *strm, int last)
Packit 08bd4c
{
Packit 08bd4c
	struct lzh_dec *ds = strm->ds;
Packit 08bd4c
	struct lzh_br *br = &(ds->br);
Packit 08bd4c
	int c = 0, i;
Packit 08bd4c
	unsigned rbits;
Packit 08bd4c
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		switch (ds->state) {
Packit 08bd4c
		case ST_RD_BLOCK:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Read a block number indicates how many blocks
Packit 08bd4c
			 * we will handle. The block is composed of a
Packit 08bd4c
			 * literal and a match, sometimes a literal only
Packit 08bd4c
			 * in particular, there are no reference data at
Packit 08bd4c
			 * the beginning of the decompression.
Packit 08bd4c
			 */
Packit 08bd4c
			if (!lzh_br_read_ahead_0(strm, br, 16)) {
Packit 08bd4c
				if (!last)
Packit 08bd4c
					/* We need following data. */
Packit 08bd4c
					return (ARCHIVE_OK);
Packit 08bd4c
				if (lzh_br_has(br, 8)) {
Packit 08bd4c
					/*
Packit 08bd4c
					 * It seems there are extra bits.
Packit 08bd4c
					 *  1. Compressed data is broken.
Packit 08bd4c
					 *  2. `last' flag does not properly
Packit 08bd4c
					 *     set.
Packit 08bd4c
					 */
Packit 08bd4c
					goto failed;
Packit 08bd4c
				}
Packit 08bd4c
				if (ds->w_pos > 0) {
Packit 08bd4c
					lzh_emit_window(strm, ds->w_pos);
Packit 08bd4c
					ds->w_pos = 0;
Packit 08bd4c
					return (ARCHIVE_OK);
Packit 08bd4c
				}
Packit 08bd4c
				/* End of compressed data; we have completely
Packit 08bd4c
				 * handled all compressed data. */
Packit 08bd4c
				return (ARCHIVE_EOF);
Packit 08bd4c
			}
Packit 08bd4c
			ds->blocks_avail = lzh_br_bits(br, 16);
Packit 08bd4c
			if (ds->blocks_avail == 0)
Packit 08bd4c
				goto failed;
Packit 08bd4c
			lzh_br_consume(br, 16);
Packit 08bd4c
			/*
Packit 08bd4c
			 * Read a literal table compressed in huffman
Packit 08bd4c
			 * coding.
Packit 08bd4c
			 */
Packit 08bd4c
			ds->pt.len_size = ds->literal_pt_len_size;
Packit 08bd4c
			ds->pt.len_bits = ds->literal_pt_len_bits;
Packit 08bd4c
			ds->reading_position = 0;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_PT_1:
Packit 08bd4c
			/* Note: ST_RD_PT_1, ST_RD_PT_2 and ST_RD_PT_4 are
Packit 08bd4c
			 * used in reading both a literal table and a
Packit 08bd4c
			 * position table. */
Packit 08bd4c
			if (!lzh_br_read_ahead(strm, br, ds->pt.len_bits)) {
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;/* Truncated data. */
Packit 08bd4c
				ds->state = ST_RD_PT_1;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			ds->pt.len_avail = lzh_br_bits(br, ds->pt.len_bits);
Packit 08bd4c
			lzh_br_consume(br, ds->pt.len_bits);
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_PT_2:
Packit 08bd4c
			if (ds->pt.len_avail == 0) {
Packit 08bd4c
				/* There is no bitlen. */
Packit 08bd4c
				if (!lzh_br_read_ahead(strm, br,
Packit 08bd4c
				    ds->pt.len_bits)) {
Packit 08bd4c
					if (last)
Packit 08bd4c
						goto failed;/* Truncated data.*/
Packit 08bd4c
					ds->state = ST_RD_PT_2;
Packit 08bd4c
					return (ARCHIVE_OK);
Packit 08bd4c
				}
Packit 08bd4c
				if (!lzh_make_fake_table(&(ds->pt),
Packit 08bd4c
				    lzh_br_bits(br, ds->pt.len_bits)))
Packit 08bd4c
					goto failed;/* Invalid data. */
Packit 08bd4c
				lzh_br_consume(br, ds->pt.len_bits);
Packit 08bd4c
				if (ds->reading_position)
Packit 08bd4c
					ds->state = ST_GET_LITERAL;
Packit 08bd4c
				else
Packit 08bd4c
					ds->state = ST_RD_LITERAL_1;
Packit 08bd4c
				break;
Packit 08bd4c
			} else if (ds->pt.len_avail > ds->pt.len_size)
Packit 08bd4c
				goto failed;/* Invalid data. */
Packit 08bd4c
			ds->loop = 0;
Packit 08bd4c
			memset(ds->pt.freq, 0, sizeof(ds->pt.freq));
Packit 08bd4c
			if (ds->pt.len_avail < 3 ||
Packit 08bd4c
			    ds->pt.len_size == ds->pos_pt_len_size) {
Packit 08bd4c
				ds->state = ST_RD_PT_4;
Packit 08bd4c
				break;
Packit 08bd4c
			}
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_PT_3:
Packit 08bd4c
			ds->loop = lzh_read_pt_bitlen(strm, ds->loop, 3);
Packit 08bd4c
			if (ds->loop < 3) {
Packit 08bd4c
				if (ds->loop < 0 || last)
Packit 08bd4c
					goto failed;/* Invalid data. */
Packit 08bd4c
				/* Not completed, get following data. */
Packit 08bd4c
				ds->state = ST_RD_PT_3;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			/* There are some null in bitlen of the literal. */
Packit 08bd4c
			if (!lzh_br_read_ahead(strm, br, 2)) {
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;/* Truncated data. */
Packit 08bd4c
				ds->state = ST_RD_PT_3;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			c = lzh_br_bits(br, 2);
Packit 08bd4c
			lzh_br_consume(br, 2);
Packit 08bd4c
			if (c > ds->pt.len_avail - 3)
Packit 08bd4c
				goto failed;/* Invalid data. */
Packit 08bd4c
			for (i = 3; c-- > 0 ;)
Packit 08bd4c
				ds->pt.bitlen[i++] = 0;
Packit 08bd4c
			ds->loop = i;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_PT_4:
Packit 08bd4c
			ds->loop = lzh_read_pt_bitlen(strm, ds->loop,
Packit 08bd4c
			    ds->pt.len_avail);
Packit 08bd4c
			if (ds->loop < ds->pt.len_avail) {
Packit 08bd4c
				if (ds->loop < 0 || last)
Packit 08bd4c
					goto failed;/* Invalid data. */
Packit 08bd4c
				/* Not completed, get following data. */
Packit 08bd4c
				ds->state = ST_RD_PT_4;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			if (!lzh_make_huffman_table(&(ds->pt)))
Packit 08bd4c
				goto failed;/* Invalid data */
Packit 08bd4c
			if (ds->reading_position) {
Packit 08bd4c
				ds->state = ST_GET_LITERAL;
Packit 08bd4c
				break;
Packit 08bd4c
			}
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_LITERAL_1:
Packit 08bd4c
			if (!lzh_br_read_ahead(strm, br, ds->lt.len_bits)) {
Packit 08bd4c
				if (last)
Packit 08bd4c
					goto failed;/* Truncated data. */
Packit 08bd4c
				ds->state = ST_RD_LITERAL_1;
Packit 08bd4c
				return (ARCHIVE_OK);
Packit 08bd4c
			}
Packit 08bd4c
			ds->lt.len_avail = lzh_br_bits(br, ds->lt.len_bits);
Packit 08bd4c
			lzh_br_consume(br, ds->lt.len_bits);
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_LITERAL_2:
Packit 08bd4c
			if (ds->lt.len_avail == 0) {
Packit 08bd4c
				/* There is no bitlen. */
Packit 08bd4c
				if (!lzh_br_read_ahead(strm, br,
Packit 08bd4c
				    ds->lt.len_bits)) {
Packit 08bd4c
					if (last)
Packit 08bd4c
						goto failed;/* Truncated data.*/
Packit 08bd4c
					ds->state = ST_RD_LITERAL_2;
Packit 08bd4c
					return (ARCHIVE_OK);
Packit 08bd4c
				}
Packit 08bd4c
				if (!lzh_make_fake_table(&(ds->lt),
Packit 08bd4c
				    lzh_br_bits(br, ds->lt.len_bits)))
Packit 08bd4c
					goto failed;/* Invalid data */
Packit 08bd4c
				lzh_br_consume(br, ds->lt.len_bits);
Packit 08bd4c
				ds->state = ST_RD_POS_DATA_1;
Packit 08bd4c
				break;
Packit 08bd4c
			} else if (ds->lt.len_avail > ds->lt.len_size)
Packit 08bd4c
				goto failed;/* Invalid data */
Packit 08bd4c
			ds->loop = 0;
Packit 08bd4c
			memset(ds->lt.freq, 0, sizeof(ds->lt.freq));
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_LITERAL_3:
Packit 08bd4c
			i = ds->loop;
Packit 08bd4c
			while (i < ds->lt.len_avail) {
Packit 08bd4c
				if (!lzh_br_read_ahead(strm, br,
Packit 08bd4c
				    ds->pt.max_bits)) {
Packit 08bd4c
					if (last)
Packit 08bd4c
						goto failed;/* Truncated data.*/
Packit 08bd4c
					ds->loop = i;
Packit 08bd4c
					ds->state = ST_RD_LITERAL_3;
Packit 08bd4c
					return (ARCHIVE_OK);
Packit 08bd4c
				}
Packit 08bd4c
				rbits = lzh_br_bits(br, ds->pt.max_bits);
Packit 08bd4c
				c = lzh_decode_huffman(&(ds->pt), rbits);
Packit 08bd4c
				if (c > 2) {
Packit 08bd4c
					/* Note: 'c' will never be more than
Packit 08bd4c
					 * eighteen since it's limited by
Packit 08bd4c
					 * PT_BITLEN_SIZE, which is being set
Packit 08bd4c
					 * to ds->pt.len_size through
Packit 08bd4c
					 * ds->literal_pt_len_size. */
Packit 08bd4c
					lzh_br_consume(br, ds->pt.bitlen[c]);
Packit 08bd4c
					c -= 2;
Packit 08bd4c
					ds->lt.freq[c]++;
Packit 08bd4c
					ds->lt.bitlen[i++] = c;
Packit 08bd4c
				} else if (c == 0) {
Packit 08bd4c
					lzh_br_consume(br, ds->pt.bitlen[c]);
Packit 08bd4c
					ds->lt.bitlen[i++] = 0;
Packit 08bd4c
				} else {
Packit 08bd4c
					/* c == 1 or c == 2 */
Packit 08bd4c
					int n = (c == 1)?4:9;
Packit 08bd4c
					if (!lzh_br_read_ahead(strm, br,
Packit 08bd4c
					     ds->pt.bitlen[c] + n)) {
Packit 08bd4c
						if (last) /* Truncated data. */
Packit 08bd4c
							goto failed;
Packit 08bd4c
						ds->loop = i;
Packit 08bd4c
						ds->state = ST_RD_LITERAL_3;
Packit 08bd4c
						return (ARCHIVE_OK);
Packit 08bd4c
					}
Packit 08bd4c
					lzh_br_consume(br, ds->pt.bitlen[c]);
Packit 08bd4c
					c = lzh_br_bits(br, n);
Packit 08bd4c
					lzh_br_consume(br, n);
Packit 08bd4c
					c += (n == 4)?3:20;
Packit 08bd4c
					if (i + c > ds->lt.len_avail)
Packit 08bd4c
						goto failed;/* Invalid data */
Packit 08bd4c
					memset(&(ds->lt.bitlen[i]), 0, c);
Packit 08bd4c
					i += c;
Packit 08bd4c
				}
Packit 08bd4c
			}
Packit 08bd4c
			if (i > ds->lt.len_avail ||
Packit 08bd4c
			    !lzh_make_huffman_table(&(ds->lt)))
Packit 08bd4c
				goto failed;/* Invalid data */
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_RD_POS_DATA_1:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Read a position table compressed in huffman
Packit 08bd4c
			 * coding.
Packit 08bd4c
			 */
Packit 08bd4c
			ds->pt.len_size = ds->pos_pt_len_size;
Packit 08bd4c
			ds->pt.len_bits = ds->pos_pt_len_bits;
Packit 08bd4c
			ds->reading_position = 1;
Packit 08bd4c
			ds->state = ST_RD_PT_1;
Packit 08bd4c
			break;
Packit 08bd4c
		case ST_GET_LITERAL:
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
lzh_decode_blocks(struct lzh_stream *strm, int last)
Packit 08bd4c
{
Packit 08bd4c
	struct lzh_dec *ds = strm->ds;
Packit 08bd4c
	struct lzh_br bre = ds->br;
Packit 08bd4c
	struct huffman *lt = &(ds->lt);
Packit 08bd4c
	struct huffman *pt = &(ds->pt);
Packit 08bd4c
	unsigned char *w_buff = ds->w_buff;
Packit 08bd4c
	unsigned char *lt_bitlen = lt->bitlen;
Packit 08bd4c
	unsigned char *pt_bitlen = pt->bitlen;
Packit 08bd4c
	int blocks_avail = ds->blocks_avail, c = 0;
Packit 08bd4c
	int 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 lt_max_bits = lt->max_bits, pt_max_bits = pt->max_bits;
Packit 08bd4c
	int state = ds->state;
Packit 08bd4c
Packit 08bd4c
	for (;;) {
Packit 08bd4c
		switch (state) {
Packit 08bd4c
		case ST_GET_LITERAL:
Packit 08bd4c
			for (;;) {
Packit 08bd4c
				if (blocks_avail == 0) {
Packit 08bd4c
					/* We have decoded all blocks.
Packit 08bd4c
					 * Let's handle next blocks. */
Packit 08bd4c
					ds->state = ST_RD_BLOCK;
Packit 08bd4c
					ds->br = bre;
Packit 08bd4c
					ds->blocks_avail = 0;
Packit 08bd4c
					ds->w_pos = w_pos;
Packit 08bd4c
					ds->copy_pos = 0;
Packit 08bd4c
					return (100);
Packit 08bd4c
				}
Packit 08bd4c
Packit 08bd4c
				/* lzh_br_read_ahead() always try to fill the
Packit 08bd4c
				 * cache buffer up. In specific situation we
Packit 08bd4c
				 * are close to the end of the data, the cache
Packit 08bd4c
				 * buffer will not be full and thus we have to
Packit 08bd4c
				 * determine if the cache buffer has some bits
Packit 08bd4c
				 * as much as we need after lzh_br_read_ahead()
Packit 08bd4c
				 * failed. */
Packit 08bd4c
				if (!lzh_br_read_ahead(strm, &bre,
Packit 08bd4c
				    lt_max_bits)) {
Packit 08bd4c
					if (!last)
Packit 08bd4c
						goto next_data;
Packit 08bd4c
					/* Remaining bits are less than
Packit 08bd4c
					 * maximum bits(lt.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 = lzh_decode_huffman(lt,
Packit 08bd4c
					      lzh_br_bits_forced(&bre,
Packit 08bd4c
					        lt_max_bits));
Packit 08bd4c
					lzh_br_consume(&bre, lt_bitlen[c]);
Packit 08bd4c
					if (!lzh_br_has(&bre, 0))
Packit 08bd4c
						goto failed;/* Over read. */
Packit 08bd4c
				} else {
Packit 08bd4c
					c = lzh_decode_huffman(lt,
Packit 08bd4c
					      lzh_br_bits(&bre, lt_max_bits));
Packit 08bd4c
					lzh_br_consume(&bre, lt_bitlen[c]);
Packit 08bd4c
				}
Packit 08bd4c
				blocks_avail--;
Packit 08bd4c
				if (c > UCHAR_MAX)
Packit 08bd4c
					/* Current block is a match data. */
Packit 08bd4c
					break;
Packit 08bd4c
				/*
Packit 08bd4c
				 * 'c' is exactly a 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
				if (++w_pos >= w_size) {
Packit 08bd4c
					w_pos = 0;
Packit 08bd4c
					lzh_emit_window(strm, w_size);
Packit 08bd4c
					goto next_data;
Packit 08bd4c
				}
Packit 08bd4c
			}
Packit 08bd4c
			/* 'c' is the length of a match pattern we have
Packit 08bd4c
			 * already extracted, which has be stored in
Packit 08bd4c
			 * window(ds->w_buff). */
Packit 08bd4c
			copy_len = c - (UCHAR_MAX + 1) + MINMATCH;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_GET_POS_1:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Get a reference position. 
Packit 08bd4c
			 */
Packit 08bd4c
			if (!lzh_br_read_ahead(strm, &bre, pt_max_bits)) {
Packit 08bd4c
				if (!last) {
Packit 08bd4c
					state = ST_GET_POS_1;
Packit 08bd4c
					ds->copy_len = copy_len;
Packit 08bd4c
					goto next_data;
Packit 08bd4c
				}
Packit 08bd4c
				copy_pos = lzh_decode_huffman(pt,
Packit 08bd4c
				    lzh_br_bits_forced(&bre, pt_max_bits));
Packit 08bd4c
				lzh_br_consume(&bre, pt_bitlen[copy_pos]);
Packit 08bd4c
				if (!lzh_br_has(&bre, 0))
Packit 08bd4c
					goto failed;/* Over read. */
Packit 08bd4c
			} else {
Packit 08bd4c
				copy_pos = lzh_decode_huffman(pt,
Packit 08bd4c
				    lzh_br_bits(&bre, pt_max_bits));
Packit 08bd4c
				lzh_br_consume(&bre, pt_bitlen[copy_pos]);
Packit 08bd4c
			}
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_GET_POS_2:
Packit 08bd4c
			if (copy_pos > 1) {
Packit 08bd4c
				/* We need an additional adjustment number to
Packit 08bd4c
				 * the position. */
Packit 08bd4c
				int p = copy_pos - 1;
Packit 08bd4c
				if (!lzh_br_read_ahead(strm, &bre, p)) {
Packit 08bd4c
					if (last)
Packit 08bd4c
						goto failed;/* Truncated data.*/
Packit 08bd4c
					state = ST_GET_POS_2;
Packit 08bd4c
					ds->copy_len = copy_len;
Packit 08bd4c
					ds->copy_pos = copy_pos;
Packit 08bd4c
					goto next_data;
Packit 08bd4c
				}
Packit 08bd4c
				copy_pos = (1 << p) + lzh_br_bits(&bre, p);
Packit 08bd4c
				lzh_br_consume(&bre, p);
Packit 08bd4c
			}
Packit 08bd4c
			/* The position is actually a distance from the last
Packit 08bd4c
			 * code we had extracted and thus we have to convert
Packit 08bd4c
			 * it to a position of the window. */
Packit 08bd4c
			copy_pos = (w_pos - copy_pos - 1) & w_mask;
Packit 08bd4c
			/* FALL THROUGH */
Packit 08bd4c
		case ST_COPY_DATA:
Packit 08bd4c
			/*
Packit 08bd4c
			 * Copy `copy_len' bytes as extracted data from
Packit 08bd4c
			 * the window into the output buffer.
Packit 08bd4c
			 */
Packit 08bd4c
			for (;;) {
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 ((copy_pos + l < w_pos)
Packit 08bd4c
				    || (w_pos + l < copy_pos)) {
Packit 08bd4c
					/* No overlap. */
Packit 08bd4c
					memcpy(w_buff + w_pos,
Packit 08bd4c
					    w_buff + copy_pos, l);
Packit 08bd4c
				} else {
Packit 08bd4c
					const unsigned char *s;
Packit 08bd4c
					unsigned char *d;
Packit 08bd4c
					int li;
Packit 08bd4c
Packit 08bd4c
					d = w_buff + w_pos;
Packit 08bd4c
					s = w_buff + copy_pos;
Packit 08bd4c
					for (li = 0; li < l-1;) {
Packit 08bd4c
						d[li] = s[li];li++;
Packit 08bd4c
						d[li] = s[li];li++;
Packit 08bd4c
					}
Packit 08bd4c
					if (li < l)
Packit 08bd4c
						d[li] = s[li];
Packit 08bd4c
				}
Packit 08bd4c
				w_pos += l;
Packit 08bd4c
				if (w_pos == w_size) {
Packit 08bd4c
					w_pos = 0;
Packit 08bd4c
					lzh_emit_window(strm, w_size);
Packit 08bd4c
					if (copy_len <= l)
Packit 08bd4c
						state = ST_GET_LITERAL;
Packit 08bd4c
					else {
Packit 08bd4c
						state = ST_COPY_DATA;
Packit 08bd4c
						ds->copy_len = copy_len - l;
Packit 08bd4c
						ds->copy_pos =
Packit 08bd4c
						    (copy_pos + l) & w_mask;
Packit 08bd4c
					}
Packit 08bd4c
					goto next_data;
Packit 08bd4c
				}
Packit 08bd4c
				if (copy_len <= l)
Packit 08bd4c
					/* A copy of current pattern ended. */
Packit 08bd4c
					break;
Packit 08bd4c
				copy_len -= l;
Packit 08bd4c
				copy_pos = (copy_pos + l) & w_mask;
Packit 08bd4c
			}
Packit 08bd4c
			state = ST_GET_LITERAL;
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->blocks_avail = blocks_avail;
Packit 08bd4c
	ds->state = state;
Packit 08bd4c
	ds->w_pos = w_pos;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
lzh_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
Packit 08bd4c
{
Packit 08bd4c
	int bits;
Packit 08bd4c
Packit 08bd4c
	if (hf->bitlen == NULL) {
Packit 08bd4c
		hf->bitlen = malloc(len_size * sizeof(hf->bitlen[0]));
Packit 08bd4c
		if (hf->bitlen == NULL)
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	if (hf->tbl == NULL) {
Packit 08bd4c
		if (tbl_bits < HTBL_BITS)
Packit 08bd4c
			bits = tbl_bits;
Packit 08bd4c
		else
Packit 08bd4c
			bits = HTBL_BITS;
Packit 08bd4c
		hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0]));
Packit 08bd4c
		if (hf->tbl == NULL)
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	if (hf->tree == NULL && tbl_bits > HTBL_BITS) {
Packit 08bd4c
		hf->tree_avail = 1 << (tbl_bits - HTBL_BITS + 4);
Packit 08bd4c
		hf->tree = malloc(hf->tree_avail * sizeof(hf->tree[0]));
Packit 08bd4c
		if (hf->tree == NULL)
Packit 08bd4c
			return (ARCHIVE_FATAL);
Packit 08bd4c
	}
Packit 08bd4c
	hf->len_size = (int)len_size;
Packit 08bd4c
	hf->tbl_bits = tbl_bits;
Packit 08bd4c
	return (ARCHIVE_OK);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static void
Packit 08bd4c
lzh_huffman_free(struct huffman *hf)
Packit 08bd4c
{
Packit 08bd4c
	free(hf->bitlen);
Packit 08bd4c
	free(hf->tbl);
Packit 08bd4c
	free(hf->tree);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static const char bitlen_tbl[0x400] = {
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
Packit 08bd4c
	 9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
Packit 08bd4c
	 9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
Packit 08bd4c
	 9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
Packit 08bd4c
	 9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
Packit 08bd4c
	 9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
Packit 08bd4c
	 9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
Packit 08bd4c
	 9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
Packit 08bd4c
	 9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
Packit 08bd4c
	10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
Packit 08bd4c
	10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
Packit 08bd4c
	10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
Packit 08bd4c
	10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
Packit 08bd4c
	11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
Packit 08bd4c
	11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
Packit 08bd4c
	12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
Packit 08bd4c
	13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 16,  0
Packit 08bd4c
};
Packit 08bd4c
static int
Packit 08bd4c
lzh_read_pt_bitlen(struct lzh_stream *strm, int start, int end)
Packit 08bd4c
{
Packit 08bd4c
	struct lzh_dec *ds = strm->ds;
Packit 08bd4c
	struct lzh_br *br = &(ds->br);
Packit 08bd4c
	int c, i;
Packit 08bd4c
Packit 08bd4c
	for (i = start; i < end; ) {
Packit 08bd4c
		/*
Packit 08bd4c
		 *  bit pattern     the number we need
Packit 08bd4c
		 *     000           ->  0
Packit 08bd4c
		 *     001           ->  1
Packit 08bd4c
		 *     010           ->  2
Packit 08bd4c
		 *     ...
Packit 08bd4c
		 *     110           ->  6
Packit 08bd4c
		 *     1110          ->  7
Packit 08bd4c
		 *     11110         ->  8
Packit 08bd4c
		 *     ...
Packit 08bd4c
		 *     1111111111110 ->  16
Packit 08bd4c
		 */
Packit 08bd4c
		if (!lzh_br_read_ahead(strm, br, 3))
Packit 08bd4c
			return (i);
Packit 08bd4c
		if ((c = lzh_br_bits(br, 3)) == 7) {
Packit 08bd4c
			if (!lzh_br_read_ahead(strm, br, 13))
Packit 08bd4c
				return (i);
Packit 08bd4c
			c = bitlen_tbl[lzh_br_bits(br, 13) & 0x3FF];
Packit 08bd4c
			if (c)
Packit 08bd4c
				lzh_br_consume(br, c - 3);
Packit 08bd4c
			else
Packit 08bd4c
				return (-1);/* Invalid data. */
Packit 08bd4c
		} else
Packit 08bd4c
			lzh_br_consume(br, 3);
Packit 08bd4c
		ds->pt.bitlen[i++] = c;
Packit 08bd4c
		ds->pt.freq[c]++;
Packit 08bd4c
	}
Packit 08bd4c
	return (i);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
lzh_make_fake_table(struct huffman *hf, uint16_t c)
Packit 08bd4c
{
Packit 08bd4c
	if (c >= hf->len_size)
Packit 08bd4c
		return (0);
Packit 08bd4c
	hf->tbl[0] = c;
Packit 08bd4c
	hf->max_bits = 0;
Packit 08bd4c
	hf->shift_bits = 0;
Packit 08bd4c
	hf->bitlen[hf->tbl[0]] = 0;
Packit 08bd4c
	return (1);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Make a huffman coding table.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
lzh_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 diffbits, 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 != 0x10000 || 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
	if (maxbits > HTBL_BITS) {
Packit 08bd4c
		unsigned htbl_max;
Packit 08bd4c
		uint16_t *p;
Packit 08bd4c
Packit 08bd4c
		diffbits = maxbits - HTBL_BITS;
Packit 08bd4c
		for (i = 1; i <= HTBL_BITS; i++) {
Packit 08bd4c
			bitptn[i] >>= diffbits;
Packit 08bd4c
			weight[i] >>= diffbits;
Packit 08bd4c
		}
Packit 08bd4c
		htbl_max = bitptn[HTBL_BITS] +
Packit 08bd4c
		    weight[HTBL_BITS] * hf->freq[HTBL_BITS];
Packit 08bd4c
		p = &(hf->tbl[htbl_max]);
Packit 08bd4c
		while (p < &hf->tbl[1U<
Packit 08bd4c
			*p++ = 0;
Packit 08bd4c
	} else
Packit 08bd4c
		diffbits = 0;
Packit 08bd4c
	hf->shift_bits = diffbits;
Packit 08bd4c
Packit 08bd4c
	/*
Packit 08bd4c
	 * Make the table.
Packit 08bd4c
	 */
Packit 08bd4c
	tbl_size = 1 << HTBL_BITS;
Packit 08bd4c
	tbl = hf->tbl;
Packit 08bd4c
	bitlen = hf->bitlen;
Packit 08bd4c
	len_avail = hf->len_avail;
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
		uint16_t bit;
Packit 08bd4c
		int extlen;
Packit 08bd4c
		struct htree_t *ht;
Packit 08bd4c
Packit 08bd4c
		if (bitlen[i] == 0)
Packit 08bd4c
			continue;
Packit 08bd4c
		/* Get a bit pattern */
Packit 08bd4c
		len = bitlen[i];
Packit 08bd4c
		ptn = bitptn[len];
Packit 08bd4c
		cnt = weight[len];
Packit 08bd4c
		if (len <= HTBL_BITS) {
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
			if (cnt > 7) {
Packit 08bd4c
				uint16_t *pc;
Packit 08bd4c
Packit 08bd4c
				cnt -= 8;
Packit 08bd4c
				pc = &p[cnt];
Packit 08bd4c
				pc[0] = (uint16_t)i;
Packit 08bd4c
				pc[1] = (uint16_t)i;
Packit 08bd4c
				pc[2] = (uint16_t)i;
Packit 08bd4c
				pc[3] = (uint16_t)i;
Packit 08bd4c
				pc[4] = (uint16_t)i;
Packit 08bd4c
				pc[5] = (uint16_t)i;
Packit 08bd4c
				pc[6] = (uint16_t)i;
Packit 08bd4c
				pc[7] = (uint16_t)i;
Packit 08bd4c
				if (cnt > 7) {
Packit 08bd4c
					cnt -= 8;
Packit 08bd4c
					memcpy(&p[cnt], pc,
Packit 08bd4c
						8 * sizeof(uint16_t));
Packit 08bd4c
					pc = &p[cnt];
Packit 08bd4c
					while (cnt > 15) {
Packit 08bd4c
						cnt -= 16;
Packit 08bd4c
						memcpy(&p[cnt], pc,
Packit 08bd4c
							16 * sizeof(uint16_t));
Packit 08bd4c
					}
Packit 08bd4c
				}
Packit 08bd4c
				if (cnt)
Packit 08bd4c
					memcpy(p, pc, cnt * sizeof(uint16_t));
Packit 08bd4c
			} else {
Packit 08bd4c
				while (cnt > 1) {
Packit 08bd4c
					p[--cnt] = (uint16_t)i;
Packit 08bd4c
					p[--cnt] = (uint16_t)i;
Packit 08bd4c
				}
Packit 08bd4c
				if (cnt)
Packit 08bd4c
					p[--cnt] = (uint16_t)i;
Packit 08bd4c
			}
Packit 08bd4c
			continue;
Packit 08bd4c
		}
Packit 08bd4c
Packit 08bd4c
		/*
Packit 08bd4c
		 * A bit length is too big to be housed to a direct table,
Packit 08bd4c
		 * so we use a tree model for its extra bits.
Packit 08bd4c
		 */
Packit 08bd4c
		bitptn[len] = ptn + cnt;
Packit 08bd4c
		bit = 1U << (diffbits -1);
Packit 08bd4c
		extlen = len - HTBL_BITS;
Packit 08bd4c
		
Packit 08bd4c
		p = &(tbl[ptn >> diffbits]);
Packit 08bd4c
		if (*p == 0) {
Packit 08bd4c
			*p = len_avail + hf->tree_used;
Packit 08bd4c
			ht = &(hf->tree[hf->tree_used++]);
Packit 08bd4c
			if (hf->tree_used > hf->tree_avail)
Packit 08bd4c
				return (0);/* Invalid */
Packit 08bd4c
			ht->left = 0;
Packit 08bd4c
			ht->right = 0;
Packit 08bd4c
		} else {
Packit 08bd4c
			if (*p < len_avail ||
Packit 08bd4c
			    *p >= (len_avail + hf->tree_used))
Packit 08bd4c
				return (0);/* Invalid */
Packit 08bd4c
			ht = &(hf->tree[*p - len_avail]);
Packit 08bd4c
		}
Packit 08bd4c
		while (--extlen > 0) {
Packit 08bd4c
			if (ptn & bit) {
Packit 08bd4c
				if (ht->left < len_avail) {
Packit 08bd4c
					ht->left = len_avail + hf->tree_used;
Packit 08bd4c
					ht = &(hf->tree[hf->tree_used++]);
Packit 08bd4c
					if (hf->tree_used > hf->tree_avail)
Packit 08bd4c
						return (0);/* Invalid */
Packit 08bd4c
					ht->left = 0;
Packit 08bd4c
					ht->right = 0;
Packit 08bd4c
				} else {
Packit 08bd4c
					ht = &(hf->tree[ht->left - len_avail]);
Packit 08bd4c
				}
Packit 08bd4c
			} else {
Packit 08bd4c
				if (ht->right < len_avail) {
Packit 08bd4c
					ht->right = len_avail + hf->tree_used;
Packit 08bd4c
					ht = &(hf->tree[hf->tree_used++]);
Packit 08bd4c
					if (hf->tree_used > hf->tree_avail)
Packit 08bd4c
						return (0);/* Invalid */
Packit 08bd4c
					ht->left = 0;
Packit 08bd4c
					ht->right = 0;
Packit 08bd4c
				} else {
Packit 08bd4c
					ht = &(hf->tree[ht->right - len_avail]);
Packit 08bd4c
				}
Packit 08bd4c
			}
Packit 08bd4c
			bit >>= 1;
Packit 08bd4c
		}
Packit 08bd4c
		if (ptn & bit) {
Packit 08bd4c
			if (ht->left != 0)
Packit 08bd4c
				return (0);/* Invalid */
Packit 08bd4c
			ht->left = (uint16_t)i;
Packit 08bd4c
		} else {
Packit 08bd4c
			if (ht->right != 0)
Packit 08bd4c
				return (0);/* Invalid */
Packit 08bd4c
			ht->right = (uint16_t)i;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	return (1);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
lzh_decode_huffman_tree(struct huffman *hf, unsigned rbits, int c)
Packit 08bd4c
{
Packit 08bd4c
	struct htree_t *ht;
Packit 08bd4c
	int extlen;
Packit 08bd4c
Packit 08bd4c
	ht = hf->tree;
Packit 08bd4c
	extlen = hf->shift_bits;
Packit 08bd4c
	while (c >= hf->len_avail) {
Packit 08bd4c
		c -= hf->len_avail;
Packit 08bd4c
		if (extlen-- <= 0 || c >= hf->tree_used)
Packit 08bd4c
			return (0);
Packit 08bd4c
		if (rbits & (1U << extlen))
Packit 08bd4c
			c = ht[c].left;
Packit 08bd4c
		else
Packit 08bd4c
			c = ht[c].right;
Packit 08bd4c
	}
Packit 08bd4c
	return (c);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static inline int
Packit 08bd4c
lzh_decode_huffman(struct huffman *hf, unsigned rbits)
Packit 08bd4c
{
Packit 08bd4c
	int c;
Packit 08bd4c
	/*
Packit 08bd4c
	 * At first search an index table for a bit pattern.
Packit 08bd4c
	 * If it fails, search a huffman tree for.
Packit 08bd4c
	 */
Packit 08bd4c
	c = hf->tbl[rbits >> hf->shift_bits];
Packit 08bd4c
	if (c < hf->len_avail || hf->len_avail == 0)
Packit 08bd4c
		return (c);
Packit 08bd4c
	/* This bit pattern needs to be found out at a huffman tree. */
Packit 08bd4c
	return (lzh_decode_huffman_tree(hf, rbits, c));
Packit 08bd4c
}
Packit 08bd4c