16c95142eSMartin Matuska /*-
26c95142eSMartin Matuska  * Copyright (c) 2011-2012 Michihiro NAKAJIMA
36c95142eSMartin Matuska  * All rights reserved.
46c95142eSMartin Matuska  *
56c95142eSMartin Matuska  * Redistribution and use in source and binary forms, with or without
66c95142eSMartin Matuska  * modification, are permitted provided that the following conditions
76c95142eSMartin Matuska  * are met:
86c95142eSMartin Matuska  * 1. Redistributions of source code must retain the above copyright
96c95142eSMartin Matuska  *    notice, this list of conditions and the following disclaimer.
106c95142eSMartin Matuska  * 2. Redistributions in binary form must reproduce the above copyright
116c95142eSMartin Matuska  *    notice, this list of conditions and the following disclaimer in the
126c95142eSMartin Matuska  *    documentation and/or other materials provided with the distribution.
136c95142eSMartin Matuska  *
146c95142eSMartin Matuska  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
156c95142eSMartin Matuska  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
166c95142eSMartin Matuska  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
176c95142eSMartin Matuska  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
186c95142eSMartin Matuska  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
196c95142eSMartin Matuska  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
206c95142eSMartin Matuska  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
216c95142eSMartin Matuska  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
226c95142eSMartin Matuska  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
236c95142eSMartin Matuska  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
246c95142eSMartin Matuska  */
256c95142eSMartin Matuska 
266c95142eSMartin Matuska #include "archive_platform.h"
276c95142eSMartin Matuska 
286c95142eSMartin Matuska #ifdef HAVE_ERRNO_H
296c95142eSMartin Matuska #include <errno.h>
306c95142eSMartin Matuska #endif
316c95142eSMartin Matuska #include <stdlib.h>
326c95142eSMartin Matuska #ifdef HAVE_BZLIB_H
336c95142eSMartin Matuska #include <bzlib.h>
346c95142eSMartin Matuska #endif
356c95142eSMartin Matuska #if HAVE_LZMA_H
366c95142eSMartin Matuska #include <lzma.h>
376c95142eSMartin Matuska #endif
386c95142eSMartin Matuska #ifdef HAVE_ZLIB_H
396c95142eSMartin Matuska #include <zlib.h>
406c95142eSMartin Matuska #endif
416c95142eSMartin Matuska 
426c95142eSMartin Matuska #include "archive.h"
436c95142eSMartin Matuska #ifndef HAVE_ZLIB_H
446c95142eSMartin Matuska #include "archive_crc32.h"
456c95142eSMartin Matuska #endif
466c95142eSMartin Matuska #include "archive_endian.h"
476c95142eSMartin Matuska #include "archive_entry.h"
486c95142eSMartin Matuska #include "archive_entry_locale.h"
496c95142eSMartin Matuska #include "archive_ppmd7_private.h"
506c95142eSMartin Matuska #include "archive_private.h"
516c95142eSMartin Matuska #include "archive_rb.h"
526c95142eSMartin Matuska #include "archive_string.h"
536c95142eSMartin Matuska #include "archive_write_private.h"
54f9762417SMartin Matuska #include "archive_write_set_format_private.h"
556c95142eSMartin Matuska 
566c95142eSMartin Matuska /*
576c95142eSMartin Matuska  * Codec ID
586c95142eSMartin Matuska  */
596c95142eSMartin Matuska #define _7Z_COPY	0
606c95142eSMartin Matuska #define _7Z_LZMA1	0x030101
616c95142eSMartin Matuska #define _7Z_LZMA2	0x21
626c95142eSMartin Matuska #define _7Z_DEFLATE	0x040108
636c95142eSMartin Matuska #define _7Z_BZIP2	0x040202
646c95142eSMartin Matuska #define _7Z_PPMD	0x030401
656c95142eSMartin Matuska 
666c95142eSMartin Matuska /*
676c95142eSMartin Matuska  * 7-Zip header property IDs.
686c95142eSMartin Matuska  */
696c95142eSMartin Matuska #define kEnd			0x00
706c95142eSMartin Matuska #define kHeader			0x01
716c95142eSMartin Matuska #define kArchiveProperties	0x02
726c95142eSMartin Matuska #define kAdditionalStreamsInfo	0x03
736c95142eSMartin Matuska #define kMainStreamsInfo	0x04
746c95142eSMartin Matuska #define kFilesInfo		0x05
756c95142eSMartin Matuska #define kPackInfo		0x06
766c95142eSMartin Matuska #define kUnPackInfo		0x07
776c95142eSMartin Matuska #define kSubStreamsInfo		0x08
786c95142eSMartin Matuska #define kSize			0x09
796c95142eSMartin Matuska #define kCRC			0x0A
806c95142eSMartin Matuska #define kFolder			0x0B
816c95142eSMartin Matuska #define kCodersUnPackSize	0x0C
826c95142eSMartin Matuska #define kNumUnPackStream	0x0D
836c95142eSMartin Matuska #define kEmptyStream		0x0E
846c95142eSMartin Matuska #define kEmptyFile		0x0F
856c95142eSMartin Matuska #define kAnti			0x10
866c95142eSMartin Matuska #define kName			0x11
876c95142eSMartin Matuska #define kCTime			0x12
886c95142eSMartin Matuska #define kATime			0x13
896c95142eSMartin Matuska #define kMTime			0x14
906c95142eSMartin Matuska #define kAttributes		0x15
916c95142eSMartin Matuska #define kEncodedHeader		0x17
926c95142eSMartin Matuska 
93b9128a37SMartin Matuska // Check that some windows file attribute constants are defined.
94b9128a37SMartin Matuska // Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
95b9128a37SMartin Matuska #ifndef FILE_ATTRIBUTE_READONLY
96b9128a37SMartin Matuska #define FILE_ATTRIBUTE_READONLY 0x00000001
97b9128a37SMartin Matuska #endif
98b9128a37SMartin Matuska 
99b9128a37SMartin Matuska #ifndef FILE_ATTRIBUTE_DIRECTORY
100b9128a37SMartin Matuska #define FILE_ATTRIBUTE_DIRECTORY 0x00000010
101b9128a37SMartin Matuska #endif
102b9128a37SMartin Matuska 
103b9128a37SMartin Matuska #ifndef FILE_ATTRIBUTE_ARCHIVE
104b9128a37SMartin Matuska #define FILE_ATTRIBUTE_ARCHIVE 0x00000020
105b9128a37SMartin Matuska #endif
106b9128a37SMartin Matuska 
107b9128a37SMartin Matuska // This value is defined in 7zip with the comment "trick for Unix".
108b9128a37SMartin Matuska //
109b9128a37SMartin Matuska // 7z archives created on unix have this bit set in the high 16 bits of
110b9128a37SMartin Matuska // the attr field along with the unix permissions.
111b9128a37SMartin Matuska #define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000
112b9128a37SMartin Matuska 
1136c95142eSMartin Matuska enum la_zaction {
1146c95142eSMartin Matuska 	ARCHIVE_Z_FINISH,
1156c95142eSMartin Matuska 	ARCHIVE_Z_RUN
1166c95142eSMartin Matuska };
1176c95142eSMartin Matuska 
1186c95142eSMartin Matuska /*
1196c95142eSMartin Matuska  * A stream object of universal compressor.
1206c95142eSMartin Matuska  */
1216c95142eSMartin Matuska struct la_zstream {
1226c95142eSMartin Matuska 	const uint8_t		*next_in;
1236c95142eSMartin Matuska 	size_t			 avail_in;
1246c95142eSMartin Matuska 	uint64_t		 total_in;
1256c95142eSMartin Matuska 
1266c95142eSMartin Matuska 	uint8_t			*next_out;
1276c95142eSMartin Matuska 	size_t			 avail_out;
1286c95142eSMartin Matuska 	uint64_t		 total_out;
1296c95142eSMartin Matuska 
1306c95142eSMartin Matuska 	uint32_t		 prop_size;
1316c95142eSMartin Matuska 	uint8_t			*props;
1326c95142eSMartin Matuska 
1336c95142eSMartin Matuska 	int			 valid;
1346c95142eSMartin Matuska 	void			*real_stream;
1356c95142eSMartin Matuska 	int			 (*code) (struct archive *a,
1366c95142eSMartin Matuska 				    struct la_zstream *lastrm,
1376c95142eSMartin Matuska 				    enum la_zaction action);
1386c95142eSMartin Matuska 	int			 (*end)(struct archive *a,
1396c95142eSMartin Matuska 				    struct la_zstream *lastrm);
1406c95142eSMartin Matuska };
1416c95142eSMartin Matuska 
1426c95142eSMartin Matuska #define PPMD7_DEFAULT_ORDER	6
1436c95142eSMartin Matuska #define PPMD7_DEFAULT_MEM_SIZE	(1 << 24)
1446c95142eSMartin Matuska 
1456c95142eSMartin Matuska struct ppmd_stream {
1466c95142eSMartin Matuska 	int			 stat;
1476c95142eSMartin Matuska 	CPpmd7			 ppmd7_context;
1486c95142eSMartin Matuska 	CPpmd7z_RangeEnc	 range_enc;
1496c95142eSMartin Matuska 	IByteOut		 byteout;
1506c95142eSMartin Matuska 	uint8_t			*buff;
1516c95142eSMartin Matuska 	uint8_t			*buff_ptr;
1526c95142eSMartin Matuska 	uint8_t			*buff_end;
1536c95142eSMartin Matuska 	size_t			 buff_bytes;
1546c95142eSMartin Matuska };
1556c95142eSMartin Matuska 
1566c95142eSMartin Matuska struct coder {
1576c95142eSMartin Matuska 	unsigned		 codec;
1586c95142eSMartin Matuska 	size_t			 prop_size;
1596c95142eSMartin Matuska 	uint8_t			*props;
1606c95142eSMartin Matuska };
1616c95142eSMartin Matuska 
1626c95142eSMartin Matuska struct file {
1636c95142eSMartin Matuska 	struct archive_rb_node	 rbnode;
1646c95142eSMartin Matuska 
1656c95142eSMartin Matuska 	struct file		*next;
1666c95142eSMartin Matuska 	unsigned		 name_len;
1676c95142eSMartin Matuska 	uint8_t			*utf16name;/* UTF16-LE name. */
1686c95142eSMartin Matuska 	uint64_t		 size;
1696c95142eSMartin Matuska 	unsigned		 flg;
1706c95142eSMartin Matuska #define MTIME_IS_SET	(1<<0)
1716c95142eSMartin Matuska #define ATIME_IS_SET	(1<<1)
1726c95142eSMartin Matuska #define CTIME_IS_SET	(1<<2)
1736c95142eSMartin Matuska #define CRC32_IS_SET	(1<<3)
1746c95142eSMartin Matuska #define HAS_STREAM	(1<<4)
1756c95142eSMartin Matuska 
1766c95142eSMartin Matuska 	struct {
1776c95142eSMartin Matuska 		time_t		 time;
1786c95142eSMartin Matuska 		long		 time_ns;
1796c95142eSMartin Matuska 	}			 times[3];
1806c95142eSMartin Matuska #define MTIME 0
1816c95142eSMartin Matuska #define ATIME 1
1826c95142eSMartin Matuska #define CTIME 2
1836c95142eSMartin Matuska 
1846c95142eSMartin Matuska 	mode_t			 mode;
1856c95142eSMartin Matuska 	uint32_t		 crc32;
1866c95142eSMartin Matuska 
18767ecab6fSDimitry Andric 	unsigned int		 dir:1;
1886c95142eSMartin Matuska };
1896c95142eSMartin Matuska 
1906c95142eSMartin Matuska struct _7zip {
1916c95142eSMartin Matuska 	int			 temp_fd;
1926c95142eSMartin Matuska 	uint64_t		 temp_offset;
1936c95142eSMartin Matuska 
1946c95142eSMartin Matuska 	struct file		*cur_file;
1956c95142eSMartin Matuska 	size_t			 total_number_entry;
1966c95142eSMartin Matuska 	size_t			 total_number_nonempty_entry;
1976c95142eSMartin Matuska 	size_t			 total_number_empty_entry;
1986c95142eSMartin Matuska 	size_t			 total_number_dir_entry;
1996c95142eSMartin Matuska 	size_t			 total_bytes_entry_name;
2006c95142eSMartin Matuska 	size_t			 total_number_time_defined[3];
2016c95142eSMartin Matuska 	uint64_t		 total_bytes_compressed;
2026c95142eSMartin Matuska 	uint64_t		 total_bytes_uncompressed;
2036c95142eSMartin Matuska 	uint64_t		 entry_bytes_remaining;
2046c95142eSMartin Matuska 	uint32_t		 entry_crc32;
2056c95142eSMartin Matuska 	uint32_t		 precode_crc32;
2066c95142eSMartin Matuska 	uint32_t		 encoded_crc32;
2076c95142eSMartin Matuska 	int			 crc32flg;
2086c95142eSMartin Matuska #define	PRECODE_CRC32	1
2096c95142eSMartin Matuska #define	ENCODED_CRC32	2
2106c95142eSMartin Matuska 
2116c95142eSMartin Matuska 	unsigned		 opt_compression;
2126c95142eSMartin Matuska 	int			 opt_compression_level;
2136c95142eSMartin Matuska 
2146c95142eSMartin Matuska 	struct la_zstream	 stream;
2156c95142eSMartin Matuska 	struct coder		 coder;
2166c95142eSMartin Matuska 
2176c95142eSMartin Matuska 	struct archive_string_conv *sconv;
2186c95142eSMartin Matuska 
2196c95142eSMartin Matuska 	/*
2206c95142eSMartin Matuska 	 * Compressed data buffer.
2216c95142eSMartin Matuska 	 */
222fd082e96SMartin Matuska 	unsigned char		 wbuff[512 * 20 * 6];
2236c95142eSMartin Matuska 	size_t			 wbuff_remaining;
2246c95142eSMartin Matuska 
2256c95142eSMartin Matuska 	/*
2266c95142eSMartin Matuska 	 * The list of the file entries which has its contents is used to
2276c95142eSMartin Matuska 	 * manage struct file objects.
228a2e802b7SMartin Matuska 	 * We use 'next' (a member of struct file) to chain.
2296c95142eSMartin Matuska 	 */
2306c95142eSMartin Matuska 	struct {
2316c95142eSMartin Matuska 		struct file	*first;
2326c95142eSMartin Matuska 		struct file	**last;
2336c95142eSMartin Matuska 	}			 file_list, empty_list;
2346c95142eSMartin Matuska 	struct archive_rb_tree	 rbtree;/* for empty files */
2356c95142eSMartin Matuska };
2366c95142eSMartin Matuska 
2376c95142eSMartin Matuska static int	_7z_options(struct archive_write *,
2386c95142eSMartin Matuska 		    const char *, const char *);
2396c95142eSMartin Matuska static int	_7z_write_header(struct archive_write *,
2406c95142eSMartin Matuska 		    struct archive_entry *);
2416c95142eSMartin Matuska static ssize_t	_7z_write_data(struct archive_write *,
2426c95142eSMartin Matuska 		    const void *, size_t);
2436c95142eSMartin Matuska static int	_7z_finish_entry(struct archive_write *);
2446c95142eSMartin Matuska static int	_7z_close(struct archive_write *);
2456c95142eSMartin Matuska static int	_7z_free(struct archive_write *);
2466c95142eSMartin Matuska static int	file_cmp_node(const struct archive_rb_node *,
2476c95142eSMartin Matuska 		    const struct archive_rb_node *);
2486c95142eSMartin Matuska static int	file_cmp_key(const struct archive_rb_node *, const void *);
2496c95142eSMartin Matuska static int	file_new(struct archive_write *a, struct archive_entry *,
2506c95142eSMartin Matuska 		    struct file **);
2516c95142eSMartin Matuska static void	file_free(struct file *);
2526c95142eSMartin Matuska static void	file_register(struct _7zip *, struct file *);
2536c95142eSMartin Matuska static void	file_register_empty(struct _7zip *, struct file *);
2546c95142eSMartin Matuska static void	file_init_register(struct _7zip *);
2556c95142eSMartin Matuska static void	file_init_register_empty(struct _7zip *);
2566c95142eSMartin Matuska static void	file_free_register(struct _7zip *);
2576c95142eSMartin Matuska static ssize_t	compress_out(struct archive_write *, const void *, size_t ,
2586c95142eSMartin Matuska 		    enum la_zaction);
2596c95142eSMartin Matuska static int	compression_init_encoder_copy(struct archive *,
2606c95142eSMartin Matuska 		    struct la_zstream *);
2616c95142eSMartin Matuska static int	compression_code_copy(struct archive *,
2626c95142eSMartin Matuska 		    struct la_zstream *, enum la_zaction);
2636c95142eSMartin Matuska static int	compression_end_copy(struct archive *, struct la_zstream *);
2646c95142eSMartin Matuska static int	compression_init_encoder_deflate(struct archive *,
2656c95142eSMartin Matuska 		    struct la_zstream *, int, int);
2666c95142eSMartin Matuska #ifdef HAVE_ZLIB_H
2676c95142eSMartin Matuska static int	compression_code_deflate(struct archive *,
2686c95142eSMartin Matuska 		    struct la_zstream *, enum la_zaction);
2696c95142eSMartin Matuska static int	compression_end_deflate(struct archive *, struct la_zstream *);
2706c95142eSMartin Matuska #endif
2716c95142eSMartin Matuska static int	compression_init_encoder_bzip2(struct archive *,
2726c95142eSMartin Matuska 		    struct la_zstream *, int);
2736c95142eSMartin Matuska #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
2746c95142eSMartin Matuska static int	compression_code_bzip2(struct archive *,
2756c95142eSMartin Matuska 		    struct la_zstream *, enum la_zaction);
2766c95142eSMartin Matuska static int	compression_end_bzip2(struct archive *, struct la_zstream *);
2776c95142eSMartin Matuska #endif
2786c95142eSMartin Matuska static int	compression_init_encoder_lzma1(struct archive *,
2796c95142eSMartin Matuska 		    struct la_zstream *, int);
2806c95142eSMartin Matuska static int	compression_init_encoder_lzma2(struct archive *,
2816c95142eSMartin Matuska 		    struct la_zstream *, int);
2826c95142eSMartin Matuska #if defined(HAVE_LZMA_H)
2836c95142eSMartin Matuska static int	compression_code_lzma(struct archive *,
2846c95142eSMartin Matuska 		    struct la_zstream *, enum la_zaction);
2856c95142eSMartin Matuska static int	compression_end_lzma(struct archive *, struct la_zstream *);
2866c95142eSMartin Matuska #endif
2876c95142eSMartin Matuska static int	compression_init_encoder_ppmd(struct archive *,
2886c95142eSMartin Matuska 		    struct la_zstream *, unsigned, uint32_t);
2896c95142eSMartin Matuska static int	compression_code_ppmd(struct archive *,
2906c95142eSMartin Matuska 		    struct la_zstream *, enum la_zaction);
2916c95142eSMartin Matuska static int	compression_end_ppmd(struct archive *, struct la_zstream *);
2926c95142eSMartin Matuska static int	_7z_compression_init_encoder(struct archive_write *, unsigned,
2936c95142eSMartin Matuska 		    int);
2946c95142eSMartin Matuska static int	compression_code(struct archive *,
2956c95142eSMartin Matuska 		    struct la_zstream *, enum la_zaction);
2966c95142eSMartin Matuska static int	compression_end(struct archive *,
2976c95142eSMartin Matuska 		    struct la_zstream *);
2986c95142eSMartin Matuska static int	enc_uint64(struct archive_write *, uint64_t);
2996c95142eSMartin Matuska static int	make_header(struct archive_write *, uint64_t, uint64_t,
3006c95142eSMartin Matuska 		    uint64_t, int, struct coder *);
3016c95142eSMartin Matuska static int	make_streamsInfo(struct archive_write *, uint64_t, uint64_t,
3026c95142eSMartin Matuska 		    	uint64_t, int, struct coder *, int, uint32_t);
3036c95142eSMartin Matuska 
3046c95142eSMartin Matuska int
archive_write_set_format_7zip(struct archive * _a)3056c95142eSMartin Matuska archive_write_set_format_7zip(struct archive *_a)
3066c95142eSMartin Matuska {
3076c95142eSMartin Matuska 	static const struct archive_rb_tree_ops rb_ops = {
3086c95142eSMartin Matuska 		file_cmp_node, file_cmp_key
3096c95142eSMartin Matuska 	};
3106c95142eSMartin Matuska 	struct archive_write *a = (struct archive_write *)_a;
3116c95142eSMartin Matuska 	struct _7zip *zip;
3126c95142eSMartin Matuska 
3136c95142eSMartin Matuska 	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
3146c95142eSMartin Matuska 	    ARCHIVE_STATE_NEW, "archive_write_set_format_7zip");
3156c95142eSMartin Matuska 
3166c95142eSMartin Matuska 	/* If another format was already registered, unregister it. */
3176c95142eSMartin Matuska 	if (a->format_free != NULL)
3186c95142eSMartin Matuska 		(a->format_free)(a);
3196c95142eSMartin Matuska 
3206c95142eSMartin Matuska 	zip = calloc(1, sizeof(*zip));
3216c95142eSMartin Matuska 	if (zip == NULL) {
3226c95142eSMartin Matuska 		archive_set_error(&a->archive, ENOMEM,
3236c95142eSMartin Matuska 		    "Can't allocate 7-Zip data");
3246c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
3256c95142eSMartin Matuska 	}
3266c95142eSMartin Matuska 	zip->temp_fd = -1;
3276c95142eSMartin Matuska 	__archive_rb_tree_init(&(zip->rbtree), &rb_ops);
3286c95142eSMartin Matuska 	file_init_register(zip);
3296c95142eSMartin Matuska 	file_init_register_empty(zip);
3306c95142eSMartin Matuska 
3316c95142eSMartin Matuska 	/* Set default compression type and its level. */
3326c95142eSMartin Matuska #if HAVE_LZMA_H
3336c95142eSMartin Matuska 	zip->opt_compression = _7Z_LZMA1;
3346c95142eSMartin Matuska #elif defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
3356c95142eSMartin Matuska 	zip->opt_compression = _7Z_BZIP2;
3366c95142eSMartin Matuska #elif defined(HAVE_ZLIB_H)
3376c95142eSMartin Matuska 	zip->opt_compression = _7Z_DEFLATE;
3386c95142eSMartin Matuska #else
3396c95142eSMartin Matuska 	zip->opt_compression = _7Z_COPY;
3406c95142eSMartin Matuska #endif
3416c95142eSMartin Matuska 	zip->opt_compression_level = 6;
3426c95142eSMartin Matuska 
3436c95142eSMartin Matuska 	a->format_data = zip;
3446c95142eSMartin Matuska 
3456c95142eSMartin Matuska 	a->format_name = "7zip";
3466c95142eSMartin Matuska 	a->format_options = _7z_options;
3476c95142eSMartin Matuska 	a->format_write_header = _7z_write_header;
3486c95142eSMartin Matuska 	a->format_write_data = _7z_write_data;
3496c95142eSMartin Matuska 	a->format_finish_entry = _7z_finish_entry;
3506c95142eSMartin Matuska 	a->format_close = _7z_close;
3516c95142eSMartin Matuska 	a->format_free = _7z_free;
3526c95142eSMartin Matuska 	a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
3536c95142eSMartin Matuska 	a->archive.archive_format_name = "7zip";
3546c95142eSMartin Matuska 
3556c95142eSMartin Matuska 	return (ARCHIVE_OK);
3566c95142eSMartin Matuska }
3576c95142eSMartin Matuska 
3586c95142eSMartin Matuska static int
_7z_options(struct archive_write * a,const char * key,const char * value)3596c95142eSMartin Matuska _7z_options(struct archive_write *a, const char *key, const char *value)
3606c95142eSMartin Matuska {
3616c95142eSMartin Matuska 	struct _7zip *zip;
3626c95142eSMartin Matuska 
3636c95142eSMartin Matuska 	zip = (struct _7zip *)a->format_data;
3646c95142eSMartin Matuska 
3656c95142eSMartin Matuska 	if (strcmp(key, "compression") == 0) {
3666c95142eSMartin Matuska 		const char *name = NULL;
3676c95142eSMartin Matuska 
3686c95142eSMartin Matuska 		if (value == NULL || strcmp(value, "copy") == 0 ||
3696c95142eSMartin Matuska 		    strcmp(value, "COPY") == 0 ||
3706c95142eSMartin Matuska 		    strcmp(value, "store") == 0 ||
3716c95142eSMartin Matuska 		    strcmp(value, "STORE") == 0)
3726c95142eSMartin Matuska 			zip->opt_compression = _7Z_COPY;
3736c95142eSMartin Matuska 		else if (strcmp(value, "deflate") == 0 ||
3746c95142eSMartin Matuska 		    strcmp(value, "DEFLATE") == 0)
3756c95142eSMartin Matuska #if HAVE_ZLIB_H
3766c95142eSMartin Matuska 			zip->opt_compression = _7Z_DEFLATE;
3776c95142eSMartin Matuska #else
3786c95142eSMartin Matuska 			name = "deflate";
3796c95142eSMartin Matuska #endif
3806c95142eSMartin Matuska 		else if (strcmp(value, "bzip2") == 0 ||
3816c95142eSMartin Matuska 		    strcmp(value, "BZIP2") == 0)
3826c95142eSMartin Matuska #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
3836c95142eSMartin Matuska 			zip->opt_compression = _7Z_BZIP2;
3846c95142eSMartin Matuska #else
3856c95142eSMartin Matuska 			name = "bzip2";
3866c95142eSMartin Matuska #endif
3876c95142eSMartin Matuska 		else if (strcmp(value, "lzma1") == 0 ||
3886c95142eSMartin Matuska 		    strcmp(value, "LZMA1") == 0)
3896c95142eSMartin Matuska #if HAVE_LZMA_H
3906c95142eSMartin Matuska 			zip->opt_compression = _7Z_LZMA1;
3916c95142eSMartin Matuska #else
3926c95142eSMartin Matuska 			name = "lzma1";
3936c95142eSMartin Matuska #endif
3946c95142eSMartin Matuska 		else if (strcmp(value, "lzma2") == 0 ||
3956c95142eSMartin Matuska 		    strcmp(value, "LZMA2") == 0)
3966c95142eSMartin Matuska #if HAVE_LZMA_H
3976c95142eSMartin Matuska 			zip->opt_compression = _7Z_LZMA2;
3986c95142eSMartin Matuska #else
3996c95142eSMartin Matuska 			name = "lzma2";
4006c95142eSMartin Matuska #endif
4016c95142eSMartin Matuska 		else if (strcmp(value, "ppmd") == 0 ||
4026c95142eSMartin Matuska 		    strcmp(value, "PPMD") == 0 ||
4036c95142eSMartin Matuska 		    strcmp(value, "PPMd") == 0)
4046c95142eSMartin Matuska 			zip->opt_compression = _7Z_PPMD;
4056c95142eSMartin Matuska 		else {
4066c95142eSMartin Matuska 			archive_set_error(&(a->archive),
4076c95142eSMartin Matuska 			    ARCHIVE_ERRNO_MISC,
408acc60b03SMartin Matuska 			    "Unknown compression name: `%s'",
4096c95142eSMartin Matuska 			    value);
4106c95142eSMartin Matuska 			return (ARCHIVE_FAILED);
4116c95142eSMartin Matuska 		}
4126c95142eSMartin Matuska 		if (name != NULL) {
4136c95142eSMartin Matuska 			archive_set_error(&(a->archive),
4146c95142eSMartin Matuska 			    ARCHIVE_ERRNO_MISC,
4156c95142eSMartin Matuska 			    "`%s' compression not supported "
4166c95142eSMartin Matuska 			    "on this platform",
4176c95142eSMartin Matuska 			    name);
4186c95142eSMartin Matuska 			return (ARCHIVE_FAILED);
4196c95142eSMartin Matuska 		}
4206c95142eSMartin Matuska 		return (ARCHIVE_OK);
4216c95142eSMartin Matuska 	}
4226c95142eSMartin Matuska 	if (strcmp(key, "compression-level") == 0) {
4236c95142eSMartin Matuska 		if (value == NULL ||
4246c95142eSMartin Matuska 		    !(value[0] >= '0' && value[0] <= '9') ||
4256c95142eSMartin Matuska 		    value[1] != '\0') {
4266c95142eSMartin Matuska 			archive_set_error(&(a->archive),
4276c95142eSMartin Matuska 			    ARCHIVE_ERRNO_MISC,
428acc60b03SMartin Matuska 			    "Illegal value `%s'",
4296c95142eSMartin Matuska 			    value);
4306c95142eSMartin Matuska 			return (ARCHIVE_FAILED);
4316c95142eSMartin Matuska 		}
4326c95142eSMartin Matuska 		zip->opt_compression_level = value[0] - '0';
4336c95142eSMartin Matuska 		return (ARCHIVE_OK);
4346c95142eSMartin Matuska 	}
4356c95142eSMartin Matuska 
4366c95142eSMartin Matuska 	/* Note: The "warn" return is just to inform the options
4376c95142eSMartin Matuska 	 * supervisor that we didn't handle it.  It will generate
4386c95142eSMartin Matuska 	 * a suitable error if no one used this option. */
4396c95142eSMartin Matuska 	return (ARCHIVE_WARN);
4406c95142eSMartin Matuska }
4416c95142eSMartin Matuska 
4426c95142eSMartin Matuska static int
_7z_write_header(struct archive_write * a,struct archive_entry * entry)4436c95142eSMartin Matuska _7z_write_header(struct archive_write *a, struct archive_entry *entry)
4446c95142eSMartin Matuska {
4456c95142eSMartin Matuska 	struct _7zip *zip;
4466c95142eSMartin Matuska 	struct file *file;
4476c95142eSMartin Matuska 	int r;
4486c95142eSMartin Matuska 
4496c95142eSMartin Matuska 	zip = (struct _7zip *)a->format_data;
4506c95142eSMartin Matuska 	zip->cur_file = NULL;
4516c95142eSMartin Matuska 	zip->entry_bytes_remaining = 0;
4526c95142eSMartin Matuska 
4536c95142eSMartin Matuska 	if (zip->sconv == NULL) {
4546c95142eSMartin Matuska 		zip->sconv = archive_string_conversion_to_charset(
4556c95142eSMartin Matuska 		    &a->archive, "UTF-16LE", 1);
4566c95142eSMartin Matuska 		if (zip->sconv == NULL)
4576c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
4586c95142eSMartin Matuska 	}
4596c95142eSMartin Matuska 
4606c95142eSMartin Matuska 	r = file_new(a, entry, &file);
4616c95142eSMartin Matuska 	if (r < ARCHIVE_WARN) {
462df422cb4SMartin Matuska 		if (file != NULL)
4636c95142eSMartin Matuska 			file_free(file);
4646c95142eSMartin Matuska 		return (r);
4656c95142eSMartin Matuska 	}
466acc60b03SMartin Matuska 	if (file->size == 0 && file->dir) {
467acc60b03SMartin Matuska 		if (!__archive_rb_tree_insert_node(&(zip->rbtree),
468acc60b03SMartin Matuska 		    (struct archive_rb_node *)file)) {
469acc60b03SMartin Matuska 			/* We have already had the same file. */
470acc60b03SMartin Matuska 			file_free(file);
471acc60b03SMartin Matuska 			return (ARCHIVE_OK);
472acc60b03SMartin Matuska 		}
473acc60b03SMartin Matuska 	}
4746c95142eSMartin Matuska 
4756c95142eSMartin Matuska 	if (file->flg & MTIME_IS_SET)
4766c95142eSMartin Matuska 		zip->total_number_time_defined[MTIME]++;
4776c95142eSMartin Matuska 	if (file->flg & CTIME_IS_SET)
4786c95142eSMartin Matuska 		zip->total_number_time_defined[CTIME]++;
4796c95142eSMartin Matuska 	if (file->flg & ATIME_IS_SET)
4806c95142eSMartin Matuska 		zip->total_number_time_defined[ATIME]++;
4816c95142eSMartin Matuska 
4826c95142eSMartin Matuska 	zip->total_number_entry++;
4836c95142eSMartin Matuska 	zip->total_bytes_entry_name += file->name_len + 2;
4846c95142eSMartin Matuska 	if (file->size == 0) {
4856c95142eSMartin Matuska 		/* Count up the number of empty files. */
4866c95142eSMartin Matuska 		zip->total_number_empty_entry++;
4876c95142eSMartin Matuska 		if (file->dir)
4886c95142eSMartin Matuska 			zip->total_number_dir_entry++;
4896c95142eSMartin Matuska 		else
4906c95142eSMartin Matuska 			file_register_empty(zip, file);
4916c95142eSMartin Matuska 		return (r);
4926c95142eSMartin Matuska 	}
4936c95142eSMartin Matuska 
4946c95142eSMartin Matuska 	/*
4956c95142eSMartin Matuska 	 * Init compression.
4966c95142eSMartin Matuska 	 */
4976c95142eSMartin Matuska 	if ((zip->total_number_entry - zip->total_number_empty_entry) == 1) {
4986c95142eSMartin Matuska 		r = _7z_compression_init_encoder(a, zip->opt_compression,
4996c95142eSMartin Matuska 			zip->opt_compression_level);
5006c95142eSMartin Matuska 		if (r < 0) {
5016c95142eSMartin Matuska 			file_free(file);
5026c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
5036c95142eSMartin Matuska 		}
5046c95142eSMartin Matuska 	}
5056c95142eSMartin Matuska 
5066c95142eSMartin Matuska 	/* Register a non-empty file. */
5076c95142eSMartin Matuska 	file_register(zip, file);
5086c95142eSMartin Matuska 
5096c95142eSMartin Matuska 	/*
5106c95142eSMartin Matuska 	 * Set the current file to cur_file to read its contents.
5116c95142eSMartin Matuska 	 */
5126c95142eSMartin Matuska 	zip->cur_file = file;
5136c95142eSMartin Matuska 
5146c95142eSMartin Matuska 
5156c95142eSMartin Matuska 	/* Save a offset of current file in temporary file. */
5166c95142eSMartin Matuska 	zip->entry_bytes_remaining = file->size;
5176c95142eSMartin Matuska 	zip->entry_crc32 = 0;
5186c95142eSMartin Matuska 
5196c95142eSMartin Matuska 	/*
5206c95142eSMartin Matuska 	 * Store a symbolic link name as file contents.
5216c95142eSMartin Matuska 	 */
5226c95142eSMartin Matuska 	if (archive_entry_filetype(entry) == AE_IFLNK) {
5236c95142eSMartin Matuska 		ssize_t bytes;
5246c95142eSMartin Matuska 		const void *p = (const void *)archive_entry_symlink(entry);
525fd082e96SMartin Matuska 		bytes = compress_out(a, p, (size_t)file->size, ARCHIVE_Z_RUN);
5266c95142eSMartin Matuska 		if (bytes < 0)
5276c95142eSMartin Matuska 			return ((int)bytes);
528acc60b03SMartin Matuska 		zip->entry_crc32 = crc32(zip->entry_crc32, p, (unsigned)bytes);
5296c95142eSMartin Matuska 		zip->entry_bytes_remaining -= bytes;
5306c95142eSMartin Matuska 	}
5316c95142eSMartin Matuska 
5326c95142eSMartin Matuska 	return (r);
5336c95142eSMartin Matuska }
5346c95142eSMartin Matuska 
5356c95142eSMartin Matuska /*
5366c95142eSMartin Matuska  * Write data to a temporary file.
5376c95142eSMartin Matuska  */
5386c95142eSMartin Matuska static int
write_to_temp(struct archive_write * a,const void * buff,size_t s)5396c95142eSMartin Matuska write_to_temp(struct archive_write *a, const void *buff, size_t s)
5406c95142eSMartin Matuska {
5416c95142eSMartin Matuska 	struct _7zip *zip;
5426c95142eSMartin Matuska 	const unsigned char *p;
5436c95142eSMartin Matuska 	ssize_t ws;
5446c95142eSMartin Matuska 
5456c95142eSMartin Matuska 	zip = (struct _7zip *)a->format_data;
5466c95142eSMartin Matuska 
5476c95142eSMartin Matuska 	/*
5486c95142eSMartin Matuska 	 * Open a temporary file.
5496c95142eSMartin Matuska 	 */
5506c95142eSMartin Matuska 	if (zip->temp_fd == -1) {
5516c95142eSMartin Matuska 		zip->temp_offset = 0;
5526c95142eSMartin Matuska 		zip->temp_fd = __archive_mktemp(NULL);
5536c95142eSMartin Matuska 		if (zip->temp_fd < 0) {
5546c95142eSMartin Matuska 			archive_set_error(&a->archive, errno,
5556c95142eSMartin Matuska 			    "Couldn't create temporary file");
5566c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
5576c95142eSMartin Matuska 		}
5586c95142eSMartin Matuska 	}
5596c95142eSMartin Matuska 
5606c95142eSMartin Matuska 	p = (const unsigned char *)buff;
5616c95142eSMartin Matuska 	while (s) {
5626c95142eSMartin Matuska 		ws = write(zip->temp_fd, p, s);
5636c95142eSMartin Matuska 		if (ws < 0) {
5646c95142eSMartin Matuska 			archive_set_error(&(a->archive), errno,
5656c95142eSMartin Matuska 			    "fwrite function failed");
5666c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
5676c95142eSMartin Matuska 		}
5686c95142eSMartin Matuska 		s -= ws;
5696c95142eSMartin Matuska 		p += ws;
5706c95142eSMartin Matuska 		zip->temp_offset += ws;
5716c95142eSMartin Matuska 	}
5726c95142eSMartin Matuska 	return (ARCHIVE_OK);
5736c95142eSMartin Matuska }
5746c95142eSMartin Matuska 
5756c95142eSMartin Matuska static ssize_t
compress_out(struct archive_write * a,const void * buff,size_t s,enum la_zaction run)5766c95142eSMartin Matuska compress_out(struct archive_write *a, const void *buff, size_t s,
5776c95142eSMartin Matuska     enum la_zaction run)
5786c95142eSMartin Matuska {
5796c95142eSMartin Matuska 	struct _7zip *zip = (struct _7zip *)a->format_data;
5806c95142eSMartin Matuska 	int r;
5816c95142eSMartin Matuska 
5826c95142eSMartin Matuska 	if (run == ARCHIVE_Z_FINISH && zip->stream.total_in == 0 && s == 0)
5836c95142eSMartin Matuska 		return (0);
5846c95142eSMartin Matuska 
5856c95142eSMartin Matuska 	if ((zip->crc32flg & PRECODE_CRC32) && s)
586acc60b03SMartin Matuska 		zip->precode_crc32 = crc32(zip->precode_crc32, buff,
587acc60b03SMartin Matuska 		    (unsigned)s);
5886c95142eSMartin Matuska 	zip->stream.next_in = (const unsigned char *)buff;
5896c95142eSMartin Matuska 	zip->stream.avail_in = s;
590acc60b03SMartin Matuska 	for (;;) {
5916c95142eSMartin Matuska 		/* Compress file data. */
5926c95142eSMartin Matuska 		r = compression_code(&(a->archive), &(zip->stream), run);
5936c95142eSMartin Matuska 		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
5946c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
5956c95142eSMartin Matuska 		if (zip->stream.avail_out == 0) {
5966c95142eSMartin Matuska 			if (write_to_temp(a, zip->wbuff, sizeof(zip->wbuff))
5976c95142eSMartin Matuska 			    != ARCHIVE_OK)
5986c95142eSMartin Matuska 				return (ARCHIVE_FATAL);
5996c95142eSMartin Matuska 			zip->stream.next_out = zip->wbuff;
6006c95142eSMartin Matuska 			zip->stream.avail_out = sizeof(zip->wbuff);
6016c95142eSMartin Matuska 			if (zip->crc32flg & ENCODED_CRC32)
6026c95142eSMartin Matuska 				zip->encoded_crc32 = crc32(zip->encoded_crc32,
6036c95142eSMartin Matuska 				    zip->wbuff, sizeof(zip->wbuff));
604acc60b03SMartin Matuska 			if (run == ARCHIVE_Z_FINISH && r != ARCHIVE_EOF)
605acc60b03SMartin Matuska 				continue;
6066c95142eSMartin Matuska 		}
607acc60b03SMartin Matuska 		if (zip->stream.avail_in == 0)
608acc60b03SMartin Matuska 			break;
609acc60b03SMartin Matuska 	}
6106c95142eSMartin Matuska 	if (run == ARCHIVE_Z_FINISH) {
6116c95142eSMartin Matuska 		uint64_t bytes = sizeof(zip->wbuff) - zip->stream.avail_out;
612fd082e96SMartin Matuska 		if (write_to_temp(a, zip->wbuff, (size_t)bytes) != ARCHIVE_OK)
6136c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
6146c95142eSMartin Matuska 		if ((zip->crc32flg & ENCODED_CRC32) && bytes)
6156c95142eSMartin Matuska 			zip->encoded_crc32 = crc32(zip->encoded_crc32,
616fd082e96SMartin Matuska 			    zip->wbuff, (unsigned)bytes);
6176c95142eSMartin Matuska 	}
6186c95142eSMartin Matuska 
6196c95142eSMartin Matuska 	return (s);
6206c95142eSMartin Matuska }
6216c95142eSMartin Matuska 
6226c95142eSMartin Matuska static ssize_t
_7z_write_data(struct archive_write * a,const void * buff,size_t s)6236c95142eSMartin Matuska _7z_write_data(struct archive_write *a, const void *buff, size_t s)
6246c95142eSMartin Matuska {
6256c95142eSMartin Matuska 	struct _7zip *zip;
6266c95142eSMartin Matuska 	ssize_t bytes;
6276c95142eSMartin Matuska 
6286c95142eSMartin Matuska 	zip = (struct _7zip *)a->format_data;
6296c95142eSMartin Matuska 
6306c95142eSMartin Matuska 	if (s > zip->entry_bytes_remaining)
631fd082e96SMartin Matuska 		s = (size_t)zip->entry_bytes_remaining;
6326c95142eSMartin Matuska 	if (s == 0 || zip->cur_file == NULL)
6336c95142eSMartin Matuska 		return (0);
6346c95142eSMartin Matuska 	bytes = compress_out(a, buff, s, ARCHIVE_Z_RUN);
6356c95142eSMartin Matuska 	if (bytes < 0)
6366c95142eSMartin Matuska 		return (bytes);
637acc60b03SMartin Matuska 	zip->entry_crc32 = crc32(zip->entry_crc32, buff, (unsigned)bytes);
6386c95142eSMartin Matuska 	zip->entry_bytes_remaining -= bytes;
6396c95142eSMartin Matuska 	return (bytes);
6406c95142eSMartin Matuska }
6416c95142eSMartin Matuska 
6426c95142eSMartin Matuska static int
_7z_finish_entry(struct archive_write * a)6436c95142eSMartin Matuska _7z_finish_entry(struct archive_write *a)
6446c95142eSMartin Matuska {
6456c95142eSMartin Matuska 	struct _7zip *zip;
6466c95142eSMartin Matuska 	size_t s;
6476c95142eSMartin Matuska 	ssize_t r;
6486c95142eSMartin Matuska 
6496c95142eSMartin Matuska 	zip = (struct _7zip *)a->format_data;
6506c95142eSMartin Matuska 	if (zip->cur_file == NULL)
6516c95142eSMartin Matuska 		return (ARCHIVE_OK);
6526c95142eSMartin Matuska 
6536c95142eSMartin Matuska 	while (zip->entry_bytes_remaining > 0) {
654fd082e96SMartin Matuska 		s = (size_t)zip->entry_bytes_remaining;
6556c95142eSMartin Matuska 		if (s > a->null_length)
6566c95142eSMartin Matuska 			s = a->null_length;
6576c95142eSMartin Matuska 		r = _7z_write_data(a, a->nulls, s);
6586c95142eSMartin Matuska 		if (r < 0)
659acc60b03SMartin Matuska 			return ((int)r);
6606c95142eSMartin Matuska 	}
6616c95142eSMartin Matuska 	zip->total_bytes_compressed += zip->stream.total_in;
6626c95142eSMartin Matuska 	zip->total_bytes_uncompressed += zip->stream.total_out;
6636c95142eSMartin Matuska 	zip->cur_file->crc32 = zip->entry_crc32;
6646c95142eSMartin Matuska 	zip->cur_file = NULL;
6656c95142eSMartin Matuska 
6666c95142eSMartin Matuska 	return (ARCHIVE_OK);
6676c95142eSMartin Matuska }
6686c95142eSMartin Matuska 
6696c95142eSMartin Matuska static int
flush_wbuff(struct archive_write * a)6706c95142eSMartin Matuska flush_wbuff(struct archive_write *a)
6716c95142eSMartin Matuska {
6726c95142eSMartin Matuska 	struct _7zip *zip;
6736c95142eSMartin Matuska 	int r;
6746c95142eSMartin Matuska 	size_t s;
6756c95142eSMartin Matuska 
6766c95142eSMartin Matuska 	zip = (struct _7zip *)a->format_data;
6776c95142eSMartin Matuska 	s = sizeof(zip->wbuff) - zip->wbuff_remaining;
6786c95142eSMartin Matuska 	r = __archive_write_output(a, zip->wbuff, s);
6796c95142eSMartin Matuska 	if (r != ARCHIVE_OK)
6806c95142eSMartin Matuska 		return (r);
6816c95142eSMartin Matuska 	zip->wbuff_remaining = sizeof(zip->wbuff);
6826c95142eSMartin Matuska 	return (r);
6836c95142eSMartin Matuska }
6846c95142eSMartin Matuska 
6856c95142eSMartin Matuska static int
copy_out(struct archive_write * a,uint64_t offset,uint64_t length)6866c95142eSMartin Matuska copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
6876c95142eSMartin Matuska {
6886c95142eSMartin Matuska 	struct _7zip *zip;
6896c95142eSMartin Matuska 	int r;
6906c95142eSMartin Matuska 
6916c95142eSMartin Matuska 	zip = (struct _7zip *)a->format_data;
6926c95142eSMartin Matuska 	if (zip->temp_offset > 0 &&
6936c95142eSMartin Matuska 	    lseek(zip->temp_fd, offset, SEEK_SET) < 0) {
6946c95142eSMartin Matuska 		archive_set_error(&(a->archive), errno, "lseek failed");
6956c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
6966c95142eSMartin Matuska 	}
6976c95142eSMartin Matuska 	while (length) {
6986c95142eSMartin Matuska 		size_t rsize;
6996c95142eSMartin Matuska 		ssize_t rs;
7006c95142eSMartin Matuska 		unsigned char *wb;
7016c95142eSMartin Matuska 
7026c95142eSMartin Matuska 		if (length > zip->wbuff_remaining)
7036c95142eSMartin Matuska 			rsize = zip->wbuff_remaining;
7046c95142eSMartin Matuska 		else
7056c95142eSMartin Matuska 			rsize = (size_t)length;
7066c95142eSMartin Matuska 		wb = zip->wbuff + (sizeof(zip->wbuff) - zip->wbuff_remaining);
7076c95142eSMartin Matuska 		rs = read(zip->temp_fd, wb, rsize);
7086c95142eSMartin Matuska 		if (rs < 0) {
7096c95142eSMartin Matuska 			archive_set_error(&(a->archive), errno,
7106c95142eSMartin Matuska 			    "Can't read temporary file(%jd)",
7116c95142eSMartin Matuska 			    (intmax_t)rs);
7126c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
7136c95142eSMartin Matuska 		}
7146c95142eSMartin Matuska 		if (rs == 0) {
7156c95142eSMartin Matuska 			archive_set_error(&(a->archive), 0,
7166c95142eSMartin Matuska 			    "Truncated 7-Zip archive");
7176c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
7186c95142eSMartin Matuska 		}
7196c95142eSMartin Matuska 		zip->wbuff_remaining -= rs;
7206c95142eSMartin Matuska 		length -= rs;
7216c95142eSMartin Matuska 		if (zip->wbuff_remaining == 0) {
7226c95142eSMartin Matuska 			r = flush_wbuff(a);
7236c95142eSMartin Matuska 			if (r != ARCHIVE_OK)
7246c95142eSMartin Matuska 				return (r);
7256c95142eSMartin Matuska 		}
7266c95142eSMartin Matuska 	}
7276c95142eSMartin Matuska 	return (ARCHIVE_OK);
7286c95142eSMartin Matuska }
7296c95142eSMartin Matuska 
7306c95142eSMartin Matuska static int
_7z_close(struct archive_write * a)7316c95142eSMartin Matuska _7z_close(struct archive_write *a)
7326c95142eSMartin Matuska {
7336c95142eSMartin Matuska 	struct _7zip *zip;
7346c95142eSMartin Matuska 	unsigned char *wb;
7356c95142eSMartin Matuska 	uint64_t header_offset, header_size, header_unpacksize;
7366c95142eSMartin Matuska 	uint64_t length;
7376c95142eSMartin Matuska 	uint32_t header_crc32;
7386c95142eSMartin Matuska 	int r;
7396c95142eSMartin Matuska 
7406c95142eSMartin Matuska 	zip = (struct _7zip *)a->format_data;
7416c95142eSMartin Matuska 
7426c95142eSMartin Matuska 	if (zip->total_number_entry > 0) {
7436c95142eSMartin Matuska 		struct archive_rb_node *n;
7446c95142eSMartin Matuska 		uint64_t data_offset, data_size, data_unpacksize;
7456c95142eSMartin Matuska 		unsigned header_compression;
7466c95142eSMartin Matuska 
7476c95142eSMartin Matuska 		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
7486c95142eSMartin Matuska 		if (r < 0)
7496c95142eSMartin Matuska 			return (r);
7506c95142eSMartin Matuska 		data_offset = 0;
7516c95142eSMartin Matuska 		data_size = zip->stream.total_out;
7526c95142eSMartin Matuska 		data_unpacksize = zip->stream.total_in;
7536c95142eSMartin Matuska 		zip->coder.codec = zip->opt_compression;
7546c95142eSMartin Matuska 		zip->coder.prop_size = zip->stream.prop_size;
7556c95142eSMartin Matuska 		zip->coder.props = zip->stream.props;
7566c95142eSMartin Matuska 		zip->stream.prop_size = 0;
7576c95142eSMartin Matuska 		zip->stream.props = NULL;
7586c95142eSMartin Matuska 		zip->total_number_nonempty_entry =
7596c95142eSMartin Matuska 		    zip->total_number_entry - zip->total_number_empty_entry;
7606c95142eSMartin Matuska 
7616c95142eSMartin Matuska 		/* Connect an empty file list. */
7626c95142eSMartin Matuska 		if (zip->empty_list.first != NULL) {
7636c95142eSMartin Matuska 			*zip->file_list.last = zip->empty_list.first;
7646c95142eSMartin Matuska 			zip->file_list.last = zip->empty_list.last;
7656c95142eSMartin Matuska 		}
7666c95142eSMartin Matuska 		/* Connect a directory file list. */
7676c95142eSMartin Matuska 		ARCHIVE_RB_TREE_FOREACH(n, &(zip->rbtree)) {
7686c95142eSMartin Matuska 			file_register(zip, (struct file *)n);
7696c95142eSMartin Matuska 		}
7706c95142eSMartin Matuska 
7716c95142eSMartin Matuska 		/*
7726c95142eSMartin Matuska 		 * NOTE: 7z command supports just LZMA1, LZMA2 and COPY for
7736c95142eSMartin Matuska 		 * the compression type for encoding the header.
7746c95142eSMartin Matuska 		 */
7756c95142eSMartin Matuska #if HAVE_LZMA_H
7766c95142eSMartin Matuska 		header_compression = _7Z_LZMA1;
777ddce862aSMartin Matuska 		if(zip->opt_compression == _7Z_LZMA2 ||
778ddce862aSMartin Matuska 		   zip->opt_compression == _7Z_COPY)
779ddce862aSMartin Matuska 			header_compression = zip->opt_compression;
780ddce862aSMartin Matuska 
7816c95142eSMartin Matuska 		/* If the stored file is only one, do not encode the header.
7826c95142eSMartin Matuska 		 * This is the same way 7z command does. */
7836c95142eSMartin Matuska 		if (zip->total_number_entry == 1)
7846c95142eSMartin Matuska 			header_compression = _7Z_COPY;
7856c95142eSMartin Matuska #else
7866c95142eSMartin Matuska 		header_compression = _7Z_COPY;
7876c95142eSMartin Matuska #endif
788ddce862aSMartin Matuska 		r = _7z_compression_init_encoder(a, header_compression,
789ddce862aSMartin Matuska 		                                 zip->opt_compression_level);
7906c95142eSMartin Matuska 		if (r < 0)
7916c95142eSMartin Matuska 			return (r);
7926c95142eSMartin Matuska 		zip->crc32flg = PRECODE_CRC32;
7936c95142eSMartin Matuska 		zip->precode_crc32 = 0;
7946c95142eSMartin Matuska 		r = make_header(a, data_offset, data_size, data_unpacksize,
7956c95142eSMartin Matuska 			1, &(zip->coder));
7966c95142eSMartin Matuska 		if (r < 0)
7976c95142eSMartin Matuska 			return (r);
7986c95142eSMartin Matuska 		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
7996c95142eSMartin Matuska 		if (r < 0)
8006c95142eSMartin Matuska 			return (r);
8016c95142eSMartin Matuska 		header_offset = data_offset + data_size;
8026c95142eSMartin Matuska 		header_size = zip->stream.total_out;
8036c95142eSMartin Matuska 		header_crc32 = zip->precode_crc32;
8046c95142eSMartin Matuska 		header_unpacksize = zip->stream.total_in;
8056c95142eSMartin Matuska 
8066c95142eSMartin Matuska 		if (header_compression != _7Z_COPY) {
8076c95142eSMartin Matuska 			/*
8086c95142eSMartin Matuska 			 * Encode the header in order to reduce the size
8096c95142eSMartin Matuska 			 * of the archive.
8106c95142eSMartin Matuska 			 */
8116c95142eSMartin Matuska 			free(zip->coder.props);
8126c95142eSMartin Matuska 			zip->coder.codec = header_compression;
8136c95142eSMartin Matuska 			zip->coder.prop_size = zip->stream.prop_size;
8146c95142eSMartin Matuska 			zip->coder.props = zip->stream.props;
8156c95142eSMartin Matuska 			zip->stream.prop_size = 0;
8166c95142eSMartin Matuska 			zip->stream.props = NULL;
8176c95142eSMartin Matuska 
8186c95142eSMartin Matuska 			r = _7z_compression_init_encoder(a, _7Z_COPY, 0);
8196c95142eSMartin Matuska 			if (r < 0)
8206c95142eSMartin Matuska 				return (r);
8216c95142eSMartin Matuska 			zip->crc32flg = ENCODED_CRC32;
8226c95142eSMartin Matuska 			zip->encoded_crc32 = 0;
8236c95142eSMartin Matuska 
8246c95142eSMartin Matuska 			/*
8256c95142eSMartin Matuska 			 * Make EncodedHeader.
8266c95142eSMartin Matuska 			 */
8276c95142eSMartin Matuska 			r = enc_uint64(a, kEncodedHeader);
8286c95142eSMartin Matuska 			if (r < 0)
8296c95142eSMartin Matuska 				return (r);
8306c95142eSMartin Matuska 			r = make_streamsInfo(a, header_offset, header_size,
8316c95142eSMartin Matuska 			      header_unpacksize, 1, &(zip->coder), 0,
8326c95142eSMartin Matuska 			      header_crc32);
8336c95142eSMartin Matuska 			if (r < 0)
8346c95142eSMartin Matuska 				return (r);
8356c95142eSMartin Matuska 			r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
8366c95142eSMartin Matuska 			if (r < 0)
8376c95142eSMartin Matuska 				return (r);
8386c95142eSMartin Matuska 			header_offset = header_offset + header_size;
8396c95142eSMartin Matuska 			header_size = zip->stream.total_out;
8406c95142eSMartin Matuska 			header_crc32 = zip->encoded_crc32;
8416c95142eSMartin Matuska 		}
8426c95142eSMartin Matuska 		zip->crc32flg = 0;
8436c95142eSMartin Matuska 	} else {
8446c95142eSMartin Matuska 		header_offset = header_size = 0;
8456c95142eSMartin Matuska 		header_crc32 = 0;
8466c95142eSMartin Matuska 	}
8476c95142eSMartin Matuska 
8486c95142eSMartin Matuska 	length = zip->temp_offset;
8496c95142eSMartin Matuska 
8506c95142eSMartin Matuska 	/*
8516c95142eSMartin Matuska 	 * Make the zip header on wbuff(write buffer).
8526c95142eSMartin Matuska 	 */
8536c95142eSMartin Matuska 	wb = zip->wbuff;
8546c95142eSMartin Matuska 	zip->wbuff_remaining = sizeof(zip->wbuff);
8556c95142eSMartin Matuska 	memcpy(&wb[0], "7z\xBC\xAF\x27\x1C", 6);
8566c95142eSMartin Matuska 	wb[6] = 0;/* Major version. */
8576c95142eSMartin Matuska 	wb[7] = 3;/* Minor version. */
8586c95142eSMartin Matuska 	archive_le64enc(&wb[12], header_offset);/* Next Header Offset */
8596c95142eSMartin Matuska 	archive_le64enc(&wb[20], header_size);/* Next Header Size */
8606c95142eSMartin Matuska 	archive_le32enc(&wb[28], header_crc32);/* Next Header CRC */
8616c95142eSMartin Matuska 	archive_le32enc(&wb[8], crc32(0, &wb[12], 20));/* Start Header CRC */
8626c95142eSMartin Matuska 	zip->wbuff_remaining -= 32;
8636c95142eSMartin Matuska 
8646c95142eSMartin Matuska 	/*
8656c95142eSMartin Matuska 	 * Read all file contents and an encoded header from the temporary
8666c95142eSMartin Matuska 	 * file and write out it.
8676c95142eSMartin Matuska 	 */
8686c95142eSMartin Matuska 	r = copy_out(a, 0, length);
8696c95142eSMartin Matuska 	if (r != ARCHIVE_OK)
8706c95142eSMartin Matuska 		return (r);
8716c95142eSMartin Matuska 	r = flush_wbuff(a);
8726c95142eSMartin Matuska 	return (r);
8736c95142eSMartin Matuska }
8746c95142eSMartin Matuska 
8756c95142eSMartin Matuska /*
8766c95142eSMartin Matuska  * Encode 64 bits value into 7-Zip's encoded UINT64 value.
8776c95142eSMartin Matuska  */
8786c95142eSMartin Matuska static int
enc_uint64(struct archive_write * a,uint64_t val)8796c95142eSMartin Matuska enc_uint64(struct archive_write *a, uint64_t val)
8806c95142eSMartin Matuska {
8816c95142eSMartin Matuska 	unsigned mask = 0x80;
8826c95142eSMartin Matuska 	uint8_t numdata[9];
8836c95142eSMartin Matuska 	int i;
8846c95142eSMartin Matuska 
8856c95142eSMartin Matuska 	numdata[0] = 0;
8866c95142eSMartin Matuska 	for (i = 1; i < (int)sizeof(numdata); i++) {
8876c95142eSMartin Matuska 		if (val < mask) {
8886c95142eSMartin Matuska 			numdata[0] |= (uint8_t)val;
8896c95142eSMartin Matuska 			break;
8906c95142eSMartin Matuska 		}
8916c95142eSMartin Matuska 		numdata[i] = (uint8_t)val;
8926c95142eSMartin Matuska 		val >>= 8;
8936c95142eSMartin Matuska 		numdata[0] |= mask;
8946c95142eSMartin Matuska 		mask >>= 1;
8956c95142eSMartin Matuska 	}
896acc60b03SMartin Matuska 	return ((int)compress_out(a, numdata, i, ARCHIVE_Z_RUN));
8976c95142eSMartin Matuska }
8986c95142eSMartin Matuska 
8996c95142eSMartin Matuska static int
make_substreamsInfo(struct archive_write * a,struct coder * coders)9006c95142eSMartin Matuska make_substreamsInfo(struct archive_write *a, struct coder *coders)
9016c95142eSMartin Matuska {
9026c95142eSMartin Matuska 	struct _7zip *zip = (struct _7zip *)a->format_data;
9036c95142eSMartin Matuska 	struct file *file;
9046c95142eSMartin Matuska 	int r;
9056c95142eSMartin Matuska 
9066c95142eSMartin Matuska 	/*
9076c95142eSMartin Matuska 	 * Make SubStreamsInfo.
9086c95142eSMartin Matuska 	 */
9096c95142eSMartin Matuska 	r = enc_uint64(a, kSubStreamsInfo);
9106c95142eSMartin Matuska 	if (r < 0)
9116c95142eSMartin Matuska 		return (r);
9126c95142eSMartin Matuska 
9136c95142eSMartin Matuska 	if (zip->total_number_nonempty_entry > 1 && coders->codec != _7Z_COPY) {
9146c95142eSMartin Matuska 		/*
9156c95142eSMartin Matuska 		 * Make NumUnPackStream.
9166c95142eSMartin Matuska 		 */
9176c95142eSMartin Matuska 		r = enc_uint64(a, kNumUnPackStream);
9186c95142eSMartin Matuska 		if (r < 0)
9196c95142eSMartin Matuska 			return (r);
9206c95142eSMartin Matuska 
9216c95142eSMartin Matuska 		/* Write numUnpackStreams */
9226c95142eSMartin Matuska 		r = enc_uint64(a, zip->total_number_nonempty_entry);
9236c95142eSMartin Matuska 		if (r < 0)
9246c95142eSMartin Matuska 			return (r);
9256c95142eSMartin Matuska 
9266c95142eSMartin Matuska 		/*
9276c95142eSMartin Matuska 		 * Make kSize.
9286c95142eSMartin Matuska 		 */
9296c95142eSMartin Matuska 		r = enc_uint64(a, kSize);
9306c95142eSMartin Matuska 		if (r < 0)
9316c95142eSMartin Matuska 			return (r);
9326c95142eSMartin Matuska 		file = zip->file_list.first;
9336c95142eSMartin Matuska 		for (;file != NULL; file = file->next) {
9346c95142eSMartin Matuska 			if (file->next == NULL ||
9356c95142eSMartin Matuska 			    file->next->size == 0)
9366c95142eSMartin Matuska 				break;
9376c95142eSMartin Matuska 			r = enc_uint64(a, file->size);
9386c95142eSMartin Matuska 			if (r < 0)
9396c95142eSMartin Matuska 				return (r);
9406c95142eSMartin Matuska 		}
9416c95142eSMartin Matuska 	}
9426c95142eSMartin Matuska 
9436c95142eSMartin Matuska 	/*
9446c95142eSMartin Matuska 	 * Make CRC.
9456c95142eSMartin Matuska 	 */
9466c95142eSMartin Matuska 	r = enc_uint64(a, kCRC);
9476c95142eSMartin Matuska 	if (r < 0)
9486c95142eSMartin Matuska 		return (r);
9496c95142eSMartin Matuska 
9506c95142eSMartin Matuska 
9516c95142eSMartin Matuska 	/* All are defined */
9526c95142eSMartin Matuska 	r = enc_uint64(a, 1);
9536c95142eSMartin Matuska 	if (r < 0)
9546c95142eSMartin Matuska 		return (r);
9556c95142eSMartin Matuska 	file = zip->file_list.first;
9566c95142eSMartin Matuska 	for (;file != NULL; file = file->next) {
9576c95142eSMartin Matuska 		uint8_t crc[4];
9586c95142eSMartin Matuska 		if (file->size == 0)
9596c95142eSMartin Matuska 			break;
9606c95142eSMartin Matuska 		archive_le32enc(crc, file->crc32);
961acc60b03SMartin Matuska 		r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
9626c95142eSMartin Matuska 		if (r < 0)
9636c95142eSMartin Matuska 			return (r);
9646c95142eSMartin Matuska 	}
9656c95142eSMartin Matuska 
9666c95142eSMartin Matuska 	/* Write End. */
9676c95142eSMartin Matuska 	r = enc_uint64(a, kEnd);
9686c95142eSMartin Matuska 	if (r < 0)
9696c95142eSMartin Matuska 		return (r);
9706c95142eSMartin Matuska 	return (ARCHIVE_OK);
9716c95142eSMartin Matuska }
9726c95142eSMartin Matuska 
9736c95142eSMartin Matuska static int
make_streamsInfo(struct archive_write * a,uint64_t offset,uint64_t pack_size,uint64_t unpack_size,int num_coder,struct coder * coders,int substrm,uint32_t header_crc)9746c95142eSMartin Matuska make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
9756c95142eSMartin Matuska     uint64_t unpack_size, int num_coder, struct coder *coders, int substrm,
9766c95142eSMartin Matuska     uint32_t header_crc)
9776c95142eSMartin Matuska {
9786c95142eSMartin Matuska 	struct _7zip *zip = (struct _7zip *)a->format_data;
9796c95142eSMartin Matuska 	uint8_t codec_buff[8];
9806c95142eSMartin Matuska 	int numFolders, fi;
9816c95142eSMartin Matuska 	int codec_size;
9826c95142eSMartin Matuska 	int i, r;
9836c95142eSMartin Matuska 
9846c95142eSMartin Matuska 	if (coders->codec == _7Z_COPY)
985acc60b03SMartin Matuska 		numFolders = (int)zip->total_number_nonempty_entry;
9866c95142eSMartin Matuska 	else
9876c95142eSMartin Matuska 		numFolders = 1;
9886c95142eSMartin Matuska 
9896c95142eSMartin Matuska 	/*
9906c95142eSMartin Matuska 	 * Make PackInfo.
9916c95142eSMartin Matuska 	 */
9926c95142eSMartin Matuska 	r = enc_uint64(a, kPackInfo);
9936c95142eSMartin Matuska 	if (r < 0)
9946c95142eSMartin Matuska 		return (r);
9956c95142eSMartin Matuska 
9966c95142eSMartin Matuska 	/* Write PackPos. */
9976c95142eSMartin Matuska 	r = enc_uint64(a, offset);
9986c95142eSMartin Matuska 	if (r < 0)
9996c95142eSMartin Matuska 		return (r);
10006c95142eSMartin Matuska 
10016c95142eSMartin Matuska 	/* Write NumPackStreams. */
10026c95142eSMartin Matuska 	r = enc_uint64(a, numFolders);
10036c95142eSMartin Matuska 	if (r < 0)
10046c95142eSMartin Matuska 		return (r);
10056c95142eSMartin Matuska 
10066c95142eSMartin Matuska 	/* Make Size. */
10076c95142eSMartin Matuska 	r = enc_uint64(a, kSize);
10086c95142eSMartin Matuska 	if (r < 0)
10096c95142eSMartin Matuska 		return (r);
10106c95142eSMartin Matuska 
10116c95142eSMartin Matuska 	if (numFolders > 1) {
10126c95142eSMartin Matuska 		struct file *file = zip->file_list.first;
10136c95142eSMartin Matuska 		for (;file != NULL; file = file->next) {
10146c95142eSMartin Matuska 			if (file->size == 0)
10156c95142eSMartin Matuska 				break;
10166c95142eSMartin Matuska 			r = enc_uint64(a, file->size);
10176c95142eSMartin Matuska 			if (r < 0)
10186c95142eSMartin Matuska 				return (r);
10196c95142eSMartin Matuska 		}
10206c95142eSMartin Matuska 	} else {
10216c95142eSMartin Matuska 		/* Write size. */
10226c95142eSMartin Matuska 		r = enc_uint64(a, pack_size);
10236c95142eSMartin Matuska 		if (r < 0)
10246c95142eSMartin Matuska 			return (r);
10256c95142eSMartin Matuska 	}
10266c95142eSMartin Matuska 
10276c95142eSMartin Matuska 	r = enc_uint64(a, kEnd);
10286c95142eSMartin Matuska 	if (r < 0)
10296c95142eSMartin Matuska 		return (r);
10306c95142eSMartin Matuska 
10316c95142eSMartin Matuska 	/*
10326c95142eSMartin Matuska 	 * Make UnPackInfo.
10336c95142eSMartin Matuska 	 */
10346c95142eSMartin Matuska 	r = enc_uint64(a, kUnPackInfo);
10356c95142eSMartin Matuska 	if (r < 0)
10366c95142eSMartin Matuska 		return (r);
10376c95142eSMartin Matuska 
10386c95142eSMartin Matuska 	/*
10396c95142eSMartin Matuska 	 * Make Folder.
10406c95142eSMartin Matuska 	 */
10416c95142eSMartin Matuska 	r = enc_uint64(a, kFolder);
10426c95142eSMartin Matuska 	if (r < 0)
10436c95142eSMartin Matuska 		return (r);
10446c95142eSMartin Matuska 
10456c95142eSMartin Matuska 	/* Write NumFolders. */
10466c95142eSMartin Matuska 	r = enc_uint64(a, numFolders);
10476c95142eSMartin Matuska 	if (r < 0)
10486c95142eSMartin Matuska 		return (r);
10496c95142eSMartin Matuska 
10506c95142eSMartin Matuska 	/* Write External. */
10516c95142eSMartin Matuska 	r = enc_uint64(a, 0);
10526c95142eSMartin Matuska 	if (r < 0)
10536c95142eSMartin Matuska 		return (r);
10546c95142eSMartin Matuska 
10556c95142eSMartin Matuska 	for (fi = 0; fi < numFolders; fi++) {
10566c95142eSMartin Matuska 		/* Write NumCoders. */
10576c95142eSMartin Matuska 		r = enc_uint64(a, num_coder);
10586c95142eSMartin Matuska 		if (r < 0)
10596c95142eSMartin Matuska 			return (r);
10606c95142eSMartin Matuska 
10616c95142eSMartin Matuska 		for (i = 0; i < num_coder; i++) {
10626c95142eSMartin Matuska 			unsigned codec_id = coders[i].codec;
10636c95142eSMartin Matuska 
10646c95142eSMartin Matuska 			/* Write Codec flag. */
10656c95142eSMartin Matuska 			archive_be64enc(codec_buff, codec_id);
10666c95142eSMartin Matuska 			for (codec_size = 8; codec_size > 0; codec_size--) {
10676c95142eSMartin Matuska 				if (codec_buff[8 - codec_size])
10686c95142eSMartin Matuska 					break;
10696c95142eSMartin Matuska 			}
10706c95142eSMartin Matuska 			if (codec_size == 0)
10716c95142eSMartin Matuska 				codec_size = 1;
10726c95142eSMartin Matuska 			if (coders[i].prop_size)
10736c95142eSMartin Matuska 				r = enc_uint64(a, codec_size | 0x20);
10746c95142eSMartin Matuska 			else
10756c95142eSMartin Matuska 				r = enc_uint64(a, codec_size);
10766c95142eSMartin Matuska 			if (r < 0)
10776c95142eSMartin Matuska 				return (r);
10786c95142eSMartin Matuska 
10796c95142eSMartin Matuska 			/* Write Codec ID. */
10806c95142eSMartin Matuska 			codec_size &= 0x0f;
1081acc60b03SMartin Matuska 			r = (int)compress_out(a, &codec_buff[8-codec_size],
10826c95142eSMartin Matuska 				codec_size, ARCHIVE_Z_RUN);
10836c95142eSMartin Matuska 			if (r < 0)
10846c95142eSMartin Matuska 				return (r);
10856c95142eSMartin Matuska 
10866c95142eSMartin Matuska 			if (coders[i].prop_size) {
10876c95142eSMartin Matuska 				/* Write Codec property size. */
10886c95142eSMartin Matuska 				r = enc_uint64(a, coders[i].prop_size);
10896c95142eSMartin Matuska 				if (r < 0)
10906c95142eSMartin Matuska 					return (r);
10916c95142eSMartin Matuska 
10926c95142eSMartin Matuska 				/* Write Codec properties. */
1093acc60b03SMartin Matuska 				r = (int)compress_out(a, coders[i].props,
10946c95142eSMartin Matuska 					coders[i].prop_size, ARCHIVE_Z_RUN);
10956c95142eSMartin Matuska 				if (r < 0)
10966c95142eSMartin Matuska 					return (r);
10976c95142eSMartin Matuska 			}
10986c95142eSMartin Matuska 		}
10996c95142eSMartin Matuska 	}
11006c95142eSMartin Matuska 
11016c95142eSMartin Matuska 	/*
11026c95142eSMartin Matuska 	 * Make CodersUnPackSize.
11036c95142eSMartin Matuska 	 */
11046c95142eSMartin Matuska 	r = enc_uint64(a, kCodersUnPackSize);
11056c95142eSMartin Matuska 	if (r < 0)
11066c95142eSMartin Matuska 		return (r);
11076c95142eSMartin Matuska 
11086c95142eSMartin Matuska 	if (numFolders > 1) {
11096c95142eSMartin Matuska 		struct file *file = zip->file_list.first;
11106c95142eSMartin Matuska 		for (;file != NULL; file = file->next) {
11116c95142eSMartin Matuska 			if (file->size == 0)
11126c95142eSMartin Matuska 				break;
11136c95142eSMartin Matuska 			r = enc_uint64(a, file->size);
11146c95142eSMartin Matuska 			if (r < 0)
11156c95142eSMartin Matuska 				return (r);
11166c95142eSMartin Matuska 		}
11176c95142eSMartin Matuska 
11186c95142eSMartin Matuska 	} else {
11196c95142eSMartin Matuska 		/* Write UnPackSize. */
11206c95142eSMartin Matuska 		r = enc_uint64(a, unpack_size);
11216c95142eSMartin Matuska 		if (r < 0)
11226c95142eSMartin Matuska 			return (r);
11236c95142eSMartin Matuska 	}
11246c95142eSMartin Matuska 
11256c95142eSMartin Matuska 	if (!substrm) {
11266c95142eSMartin Matuska 		uint8_t crc[4];
11276c95142eSMartin Matuska 		/*
11286c95142eSMartin Matuska 		 * Make CRC.
11296c95142eSMartin Matuska 		 */
11306c95142eSMartin Matuska 		r = enc_uint64(a, kCRC);
11316c95142eSMartin Matuska 		if (r < 0)
11326c95142eSMartin Matuska 			return (r);
11336c95142eSMartin Matuska 
11346c95142eSMartin Matuska 		/* All are defined */
11356c95142eSMartin Matuska 		r = enc_uint64(a, 1);
11366c95142eSMartin Matuska 		if (r < 0)
11376c95142eSMartin Matuska 			return (r);
11386c95142eSMartin Matuska 		archive_le32enc(crc, header_crc);
1139acc60b03SMartin Matuska 		r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
11406c95142eSMartin Matuska 		if (r < 0)
11416c95142eSMartin Matuska 			return (r);
11426c95142eSMartin Matuska 	}
11436c95142eSMartin Matuska 
11446c95142eSMartin Matuska 	/* Write End. */
11456c95142eSMartin Matuska 	r = enc_uint64(a, kEnd);
11466c95142eSMartin Matuska 	if (r < 0)
11476c95142eSMartin Matuska 		return (r);
11486c95142eSMartin Matuska 
11496c95142eSMartin Matuska 	if (substrm) {
11506c95142eSMartin Matuska 		/*
11516c95142eSMartin Matuska 		 * Make SubStreamsInfo.
11526c95142eSMartin Matuska 		 */
11536c95142eSMartin Matuska 		r = make_substreamsInfo(a, coders);
11546c95142eSMartin Matuska 		if (r < 0)
11556c95142eSMartin Matuska 			return (r);
11566c95142eSMartin Matuska 	}
11576c95142eSMartin Matuska 
11586c95142eSMartin Matuska 
11596c95142eSMartin Matuska 	/* Write End. */
11606c95142eSMartin Matuska 	r = enc_uint64(a, kEnd);
11616c95142eSMartin Matuska 	if (r < 0)
11626c95142eSMartin Matuska 		return (r);
11636c95142eSMartin Matuska 
11646c95142eSMartin Matuska 	return (ARCHIVE_OK);
11656c95142eSMartin Matuska }
11666c95142eSMartin Matuska 
11676c95142eSMartin Matuska 
11686c95142eSMartin Matuska #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
11696c95142eSMartin Matuska static uint64_t
utcToFiletime(time_t t,long ns)11706c95142eSMartin Matuska utcToFiletime(time_t t, long ns)
11716c95142eSMartin Matuska {
11726c95142eSMartin Matuska 	uint64_t fileTime;
11736c95142eSMartin Matuska 
11746c95142eSMartin Matuska 	fileTime = t;
11756c95142eSMartin Matuska 	fileTime *= 10000000;
11766c95142eSMartin Matuska 	fileTime += ns / 100;
11776c95142eSMartin Matuska 	fileTime += EPOC_TIME;
11786c95142eSMartin Matuska 	return (fileTime);
11796c95142eSMartin Matuska }
11806c95142eSMartin Matuska 
11816c95142eSMartin Matuska static int
make_time(struct archive_write * a,uint8_t type,unsigned flg,int ti)11826c95142eSMartin Matuska make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)
11836c95142eSMartin Matuska {
11846c95142eSMartin Matuska 	uint8_t filetime[8];
11856c95142eSMartin Matuska 	struct _7zip *zip = (struct _7zip *)a->format_data;
11866c95142eSMartin Matuska 	struct file *file;
11876c95142eSMartin Matuska 	int r;
1188fd082e96SMartin Matuska 	uint8_t b, mask;
11896c95142eSMartin Matuska 
11906c95142eSMartin Matuska 	/*
11916c95142eSMartin Matuska 	 * Make Time Bools.
11926c95142eSMartin Matuska 	 */
11936c95142eSMartin Matuska 	if (zip->total_number_time_defined[ti] == zip->total_number_entry) {
11946c95142eSMartin Matuska 		/* Write Time Type. */
11956c95142eSMartin Matuska 		r = enc_uint64(a, type);
11966c95142eSMartin Matuska 		if (r < 0)
11976c95142eSMartin Matuska 			return (r);
11986c95142eSMartin Matuska 		/* Write EmptyStream Size. */
11996c95142eSMartin Matuska 		r = enc_uint64(a, 2 + zip->total_number_entry * 8);
12006c95142eSMartin Matuska 		if (r < 0)
12016c95142eSMartin Matuska 			return (r);
12026c95142eSMartin Matuska 		/* All are defined. */
12036c95142eSMartin Matuska 		r = enc_uint64(a, 1);
12046c95142eSMartin Matuska 		if (r < 0)
12056c95142eSMartin Matuska 			return (r);
12066c95142eSMartin Matuska 	} else {
12076c95142eSMartin Matuska 		if (zip->total_number_time_defined[ti] == 0)
12086c95142eSMartin Matuska 			return (ARCHIVE_OK);
12096c95142eSMartin Matuska 
12106c95142eSMartin Matuska 		/* Write Time Type. */
12116c95142eSMartin Matuska 		r = enc_uint64(a, type);
12126c95142eSMartin Matuska 		if (r < 0)
12136c95142eSMartin Matuska 			return (r);
12146c95142eSMartin Matuska 		/* Write EmptyStream Size. */
12156c95142eSMartin Matuska 		r = enc_uint64(a, 2 + ((zip->total_number_entry + 7) >> 3)
12166c95142eSMartin Matuska 			+ zip->total_number_time_defined[ti] * 8);
12176c95142eSMartin Matuska 		if (r < 0)
12186c95142eSMartin Matuska 			return (r);
12196c95142eSMartin Matuska 
12206c95142eSMartin Matuska 		/* All are not defined. */
12216c95142eSMartin Matuska 		r = enc_uint64(a, 0);
12226c95142eSMartin Matuska 		if (r < 0)
12236c95142eSMartin Matuska 			return (r);
12246c95142eSMartin Matuska 
1225fd082e96SMartin Matuska 		b = 0;
12266c95142eSMartin Matuska 		mask = 0x80;
12276c95142eSMartin Matuska 		file = zip->file_list.first;
12286c95142eSMartin Matuska 		for (;file != NULL; file = file->next) {
12296c95142eSMartin Matuska 			if (file->flg & flg)
1230fd082e96SMartin Matuska 				b |= mask;
12316c95142eSMartin Matuska 			mask >>= 1;
12326c95142eSMartin Matuska 			if (mask == 0) {
1233acc60b03SMartin Matuska 				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
12346c95142eSMartin Matuska 				if (r < 0)
12356c95142eSMartin Matuska 					return (r);
12366c95142eSMartin Matuska 				mask = 0x80;
1237fd082e96SMartin Matuska 				b = 0;
12386c95142eSMartin Matuska 			}
12396c95142eSMartin Matuska 		}
12406c95142eSMartin Matuska 		if (mask != 0x80) {
1241acc60b03SMartin Matuska 			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
12426c95142eSMartin Matuska 			if (r < 0)
12436c95142eSMartin Matuska 				return (r);
12446c95142eSMartin Matuska 		}
12456c95142eSMartin Matuska 	}
12466c95142eSMartin Matuska 
12476c95142eSMartin Matuska 	/* External. */
12486c95142eSMartin Matuska 	r = enc_uint64(a, 0);
12496c95142eSMartin Matuska 	if (r < 0)
12506c95142eSMartin Matuska 		return (r);
12516c95142eSMartin Matuska 
12526c95142eSMartin Matuska 
12536c95142eSMartin Matuska 	/*
12546c95142eSMartin Matuska 	 * Make Times.
12556c95142eSMartin Matuska 	 */
12566c95142eSMartin Matuska 	file = zip->file_list.first;
12576c95142eSMartin Matuska 	for (;file != NULL; file = file->next) {
12586c95142eSMartin Matuska 		if ((file->flg & flg) == 0)
12596c95142eSMartin Matuska 			continue;
12606c95142eSMartin Matuska 		archive_le64enc(filetime, utcToFiletime(file->times[ti].time,
12616c95142eSMartin Matuska 			file->times[ti].time_ns));
1262acc60b03SMartin Matuska 		r = (int)compress_out(a, filetime, 8, ARCHIVE_Z_RUN);
12636c95142eSMartin Matuska 		if (r < 0)
12646c95142eSMartin Matuska 			return (r);
12656c95142eSMartin Matuska 	}
12666c95142eSMartin Matuska 
12676c95142eSMartin Matuska 	return (ARCHIVE_OK);
12686c95142eSMartin Matuska }
12696c95142eSMartin Matuska 
12706c95142eSMartin Matuska static int
make_header(struct archive_write * a,uint64_t offset,uint64_t pack_size,uint64_t unpack_size,int codernum,struct coder * coders)12716c95142eSMartin Matuska make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
12726c95142eSMartin Matuska     uint64_t unpack_size, int codernum, struct coder *coders)
12736c95142eSMartin Matuska {
12746c95142eSMartin Matuska 	struct _7zip *zip = (struct _7zip *)a->format_data;
12756c95142eSMartin Matuska 	struct file *file;
12766c95142eSMartin Matuska 	int r;
1277fd082e96SMartin Matuska 	uint8_t b, mask;
12786c95142eSMartin Matuska 
12796c95142eSMartin Matuska 	/*
12806c95142eSMartin Matuska 	 * Make FilesInfo.
12816c95142eSMartin Matuska 	 */
12826c95142eSMartin Matuska 	r = enc_uint64(a, kHeader);
12836c95142eSMartin Matuska 	if (r < 0)
12846c95142eSMartin Matuska 		return (r);
12856c95142eSMartin Matuska 
12866c95142eSMartin Matuska 	/*
12876c95142eSMartin Matuska 	 * If there are empty files only, do not write MainStreamInfo.
12886c95142eSMartin Matuska 	 */
12896c95142eSMartin Matuska 	if (zip->total_number_nonempty_entry) {
12906c95142eSMartin Matuska 		/*
12916c95142eSMartin Matuska 		 * Make MainStreamInfo.
12926c95142eSMartin Matuska 		 */
12936c95142eSMartin Matuska 		r = enc_uint64(a, kMainStreamsInfo);
12946c95142eSMartin Matuska 		if (r < 0)
12956c95142eSMartin Matuska 			return (r);
12966c95142eSMartin Matuska 		r = make_streamsInfo(a, offset, pack_size, unpack_size,
12976c95142eSMartin Matuska 		      codernum, coders, 1, 0);
12986c95142eSMartin Matuska 		if (r < 0)
12996c95142eSMartin Matuska 			return (r);
13006c95142eSMartin Matuska 	}
13016c95142eSMartin Matuska 
13026c95142eSMartin Matuska 	/*
13036c95142eSMartin Matuska 	 * Make FilesInfo.
13046c95142eSMartin Matuska 	 */
13056c95142eSMartin Matuska 	r = enc_uint64(a, kFilesInfo);
13066c95142eSMartin Matuska 	if (r < 0)
13076c95142eSMartin Matuska 		return (r);
13086c95142eSMartin Matuska 
13096c95142eSMartin Matuska 	/* Write numFiles. */
13106c95142eSMartin Matuska 	r = enc_uint64(a, zip->total_number_entry);
13116c95142eSMartin Matuska 	if (r < 0)
13126c95142eSMartin Matuska 		return (r);
13136c95142eSMartin Matuska 
13146c95142eSMartin Matuska 	if (zip->total_number_empty_entry > 0) {
13156c95142eSMartin Matuska 		/* Make EmptyStream. */
13166c95142eSMartin Matuska 		r = enc_uint64(a, kEmptyStream);
13176c95142eSMartin Matuska 		if (r < 0)
13186c95142eSMartin Matuska 			return (r);
13196c95142eSMartin Matuska 
13206c95142eSMartin Matuska 		/* Write EmptyStream Size. */
13216c95142eSMartin Matuska 		r = enc_uint64(a, (zip->total_number_entry+7)>>3);
13226c95142eSMartin Matuska 		if (r < 0)
13236c95142eSMartin Matuska 			return (r);
13246c95142eSMartin Matuska 
1325fd082e96SMartin Matuska 		b = 0;
13266c95142eSMartin Matuska 		mask = 0x80;
13276c95142eSMartin Matuska 		file = zip->file_list.first;
13286c95142eSMartin Matuska 		for (;file != NULL; file = file->next) {
13296c95142eSMartin Matuska 			if (file->size == 0)
1330fd082e96SMartin Matuska 				b |= mask;
13316c95142eSMartin Matuska 			mask >>= 1;
13326c95142eSMartin Matuska 			if (mask == 0) {
1333acc60b03SMartin Matuska 				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
13346c95142eSMartin Matuska 				if (r < 0)
13356c95142eSMartin Matuska 					return (r);
13366c95142eSMartin Matuska 				mask = 0x80;
1337fd082e96SMartin Matuska 				b = 0;
13386c95142eSMartin Matuska 			}
13396c95142eSMartin Matuska 		}
13406c95142eSMartin Matuska 		if (mask != 0x80) {
1341acc60b03SMartin Matuska 			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
13426c95142eSMartin Matuska 			if (r < 0)
13436c95142eSMartin Matuska 				return (r);
13446c95142eSMartin Matuska 		}
13456c95142eSMartin Matuska 	}
13466c95142eSMartin Matuska 
13476c95142eSMartin Matuska 	if (zip->total_number_empty_entry > zip->total_number_dir_entry) {
13486c95142eSMartin Matuska 		/* Make EmptyFile. */
13496c95142eSMartin Matuska 		r = enc_uint64(a, kEmptyFile);
13506c95142eSMartin Matuska 		if (r < 0)
13516c95142eSMartin Matuska 			return (r);
13526c95142eSMartin Matuska 
13536c95142eSMartin Matuska 		/* Write EmptyFile Size. */
13546c95142eSMartin Matuska 		r = enc_uint64(a, (zip->total_number_empty_entry + 7) >> 3);
13556c95142eSMartin Matuska 		if (r < 0)
13566c95142eSMartin Matuska 			return (r);
13576c95142eSMartin Matuska 
1358fd082e96SMartin Matuska 		b = 0;
13596c95142eSMartin Matuska 		mask = 0x80;
13606c95142eSMartin Matuska 		file = zip->file_list.first;
13616c95142eSMartin Matuska 		for (;file != NULL; file = file->next) {
13626c95142eSMartin Matuska 			if (file->size)
13636c95142eSMartin Matuska 				continue;
13646c95142eSMartin Matuska 			if (!file->dir)
1365fd082e96SMartin Matuska 				b |= mask;
13666c95142eSMartin Matuska 			mask >>= 1;
13676c95142eSMartin Matuska 			if (mask == 0) {
1368acc60b03SMartin Matuska 				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
13696c95142eSMartin Matuska 				if (r < 0)
13706c95142eSMartin Matuska 					return (r);
13716c95142eSMartin Matuska 				mask = 0x80;
1372fd082e96SMartin Matuska 				b = 0;
13736c95142eSMartin Matuska 			}
13746c95142eSMartin Matuska 		}
13756c95142eSMartin Matuska 		if (mask != 0x80) {
1376acc60b03SMartin Matuska 			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
13776c95142eSMartin Matuska 			if (r < 0)
13786c95142eSMartin Matuska 				return (r);
13796c95142eSMartin Matuska 		}
13806c95142eSMartin Matuska 	}
13816c95142eSMartin Matuska 
13826c95142eSMartin Matuska 	/* Make Name. */
13836c95142eSMartin Matuska 	r = enc_uint64(a, kName);
13846c95142eSMartin Matuska 	if (r < 0)
13856c95142eSMartin Matuska 		return (r);
13866c95142eSMartin Matuska 
13872dbf8c4aSMartin Matuska 	/* Write Name size. */
13886c95142eSMartin Matuska 	r = enc_uint64(a, zip->total_bytes_entry_name+1);
13896c95142eSMartin Matuska 	if (r < 0)
13906c95142eSMartin Matuska 		return (r);
13916c95142eSMartin Matuska 
13926c95142eSMartin Matuska 	/* Write dmy byte. */
13936c95142eSMartin Matuska 	r = enc_uint64(a, 0);
13946c95142eSMartin Matuska 	if (r < 0)
13956c95142eSMartin Matuska 		return (r);
13966c95142eSMartin Matuska 
13976c95142eSMartin Matuska 	file = zip->file_list.first;
13986c95142eSMartin Matuska 	for (;file != NULL; file = file->next) {
1399acc60b03SMartin Matuska 		r = (int)compress_out(a, file->utf16name, file->name_len+2,
14006c95142eSMartin Matuska 			ARCHIVE_Z_RUN);
14016c95142eSMartin Matuska 		if (r < 0)
14026c95142eSMartin Matuska 			return (r);
14036c95142eSMartin Matuska 	}
14046c95142eSMartin Matuska 
14056c95142eSMartin Matuska 	/* Make MTime. */
14066c95142eSMartin Matuska 	r = make_time(a, kMTime, MTIME_IS_SET, MTIME);
14076c95142eSMartin Matuska 	if (r < 0)
14086c95142eSMartin Matuska 		return (r);
14096c95142eSMartin Matuska 
14106c95142eSMartin Matuska 	/* Make CTime. */
14116c95142eSMartin Matuska 	r = make_time(a, kCTime, CTIME_IS_SET, CTIME);
14126c95142eSMartin Matuska 	if (r < 0)
14136c95142eSMartin Matuska 		return (r);
14146c95142eSMartin Matuska 
14156c95142eSMartin Matuska 	/* Make ATime. */
14166c95142eSMartin Matuska 	r = make_time(a, kATime, ATIME_IS_SET, ATIME);
14176c95142eSMartin Matuska 	if (r < 0)
14186c95142eSMartin Matuska 		return (r);
14196c95142eSMartin Matuska 
14206c95142eSMartin Matuska 	/* Make Attributes. */
14216c95142eSMartin Matuska 	r = enc_uint64(a, kAttributes);
14226c95142eSMartin Matuska 	if (r < 0)
14236c95142eSMartin Matuska 		return (r);
14246c95142eSMartin Matuska 
14256c95142eSMartin Matuska 	/* Write Attributes size. */
14266c95142eSMartin Matuska 	r = enc_uint64(a, 2 + zip->total_number_entry * 4);
14276c95142eSMartin Matuska 	if (r < 0)
14286c95142eSMartin Matuska 		return (r);
14296c95142eSMartin Matuska 
14306c95142eSMartin Matuska 	/* Write "All Are Defined". */
14316c95142eSMartin Matuska 	r = enc_uint64(a, 1);
14326c95142eSMartin Matuska 	if (r < 0)
14336c95142eSMartin Matuska 		return (r);
14346c95142eSMartin Matuska 
14356c95142eSMartin Matuska 	/* Write dmy byte. */
14366c95142eSMartin Matuska 	r = enc_uint64(a, 0);
14376c95142eSMartin Matuska 	if (r < 0)
14386c95142eSMartin Matuska 		return (r);
14396c95142eSMartin Matuska 
14406c95142eSMartin Matuska 	file = zip->file_list.first;
14416c95142eSMartin Matuska 	for (;file != NULL; file = file->next) {
14426c95142eSMartin Matuska 		/*
14436c95142eSMartin Matuska 		 * High 16bits is unix mode.
14446c95142eSMartin Matuska 		 * Low 16bits is Windows attributes.
14456c95142eSMartin Matuska 		 */
1446b9128a37SMartin Matuska 		uint32_t encattr, attr = 0;
1447b9128a37SMartin Matuska 
14486c95142eSMartin Matuska 		if (file->dir)
1449b9128a37SMartin Matuska 			attr |= FILE_ATTRIBUTE_DIRECTORY;
14506c95142eSMartin Matuska 		else
1451b9128a37SMartin Matuska 			attr |= FILE_ATTRIBUTE_ARCHIVE;
1452b9128a37SMartin Matuska 
14536c95142eSMartin Matuska 		if ((file->mode & 0222) == 0)
1454b9128a37SMartin Matuska 			attr |= FILE_ATTRIBUTE_READONLY;
1455b9128a37SMartin Matuska 
1456b9128a37SMartin Matuska 		attr |= FILE_ATTRIBUTE_UNIX_EXTENSION;
14576c95142eSMartin Matuska 		attr |= ((uint32_t)file->mode) << 16;
1458b9128a37SMartin Matuska 
14596c95142eSMartin Matuska 		archive_le32enc(&encattr, attr);
1460acc60b03SMartin Matuska 		r = (int)compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);
14616c95142eSMartin Matuska 		if (r < 0)
14626c95142eSMartin Matuska 			return (r);
14636c95142eSMartin Matuska 	}
14646c95142eSMartin Matuska 
14656c95142eSMartin Matuska 	/* Write End. */
14666c95142eSMartin Matuska 	r = enc_uint64(a, kEnd);
14676c95142eSMartin Matuska 	if (r < 0)
14686c95142eSMartin Matuska 		return (r);
14696c95142eSMartin Matuska 
14706c95142eSMartin Matuska 	/* Write End. */
14716c95142eSMartin Matuska 	r = enc_uint64(a, kEnd);
14726c95142eSMartin Matuska 	if (r < 0)
14736c95142eSMartin Matuska 		return (r);
14746c95142eSMartin Matuska 
14756c95142eSMartin Matuska 	return (ARCHIVE_OK);
14766c95142eSMartin Matuska }
14776c95142eSMartin Matuska 
14786c95142eSMartin Matuska 
14796c95142eSMartin Matuska static int
_7z_free(struct archive_write * a)14806c95142eSMartin Matuska _7z_free(struct archive_write *a)
14816c95142eSMartin Matuska {
14826c95142eSMartin Matuska 	struct _7zip *zip = (struct _7zip *)a->format_data;
14836c95142eSMartin Matuska 
1484cdf63a70SMartin Matuska 	/* Close the temporary file. */
1485cdf63a70SMartin Matuska 	if (zip->temp_fd >= 0)
1486cdf63a70SMartin Matuska 		close(zip->temp_fd);
1487cdf63a70SMartin Matuska 
14886c95142eSMartin Matuska 	file_free_register(zip);
14896c95142eSMartin Matuska 	compression_end(&(a->archive), &(zip->stream));
14906c95142eSMartin Matuska 	free(zip->coder.props);
14916c95142eSMartin Matuska 	free(zip);
14926c95142eSMartin Matuska 
14936c95142eSMartin Matuska 	return (ARCHIVE_OK);
14946c95142eSMartin Matuska }
14956c95142eSMartin Matuska 
14966c95142eSMartin Matuska static int
file_cmp_node(const struct archive_rb_node * n1,const struct archive_rb_node * n2)14976c95142eSMartin Matuska file_cmp_node(const struct archive_rb_node *n1,
14986c95142eSMartin Matuska     const struct archive_rb_node *n2)
14996c95142eSMartin Matuska {
15006c95142eSMartin Matuska 	const struct file *f1 = (const struct file *)n1;
15016c95142eSMartin Matuska 	const struct file *f2 = (const struct file *)n2;
15026c95142eSMartin Matuska 
15036c95142eSMartin Matuska 	if (f1->name_len == f2->name_len)
15046c95142eSMartin Matuska 		return (memcmp(f1->utf16name, f2->utf16name, f1->name_len));
15056c95142eSMartin Matuska 	return (f1->name_len > f2->name_len)?1:-1;
15066c95142eSMartin Matuska }
15076c95142eSMartin Matuska 
15086c95142eSMartin Matuska static int
file_cmp_key(const struct archive_rb_node * n,const void * key)15096c95142eSMartin Matuska file_cmp_key(const struct archive_rb_node *n, const void *key)
15106c95142eSMartin Matuska {
15116c95142eSMartin Matuska 	const struct file *f = (const struct file *)n;
15126c95142eSMartin Matuska 
15136c95142eSMartin Matuska 	return (f->name_len - *(const char *)key);
15146c95142eSMartin Matuska }
15156c95142eSMartin Matuska 
15166c95142eSMartin Matuska static int
file_new(struct archive_write * a,struct archive_entry * entry,struct file ** newfile)15176c95142eSMartin Matuska file_new(struct archive_write *a, struct archive_entry *entry,
15186c95142eSMartin Matuska     struct file **newfile)
15196c95142eSMartin Matuska {
15206c95142eSMartin Matuska 	struct _7zip *zip;
15216c95142eSMartin Matuska 	struct file *file;
15226c95142eSMartin Matuska 	const char *u16;
15236c95142eSMartin Matuska 	size_t u16len;
15246c95142eSMartin Matuska 	int ret = ARCHIVE_OK;
15256c95142eSMartin Matuska 
15266c95142eSMartin Matuska 	zip = (struct _7zip *)a->format_data;
15276c95142eSMartin Matuska 	*newfile = NULL;
15286c95142eSMartin Matuska 
15296c95142eSMartin Matuska 	file = calloc(1, sizeof(*file));
15306c95142eSMartin Matuska 	if (file == NULL) {
15316c95142eSMartin Matuska 		archive_set_error(&a->archive, ENOMEM,
15326c95142eSMartin Matuska 		    "Can't allocate memory");
15336c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
15346c95142eSMartin Matuska 	}
15356c95142eSMartin Matuska 
15366c95142eSMartin Matuska 	if (0 > archive_entry_pathname_l(entry, &u16, &u16len, zip->sconv)) {
15376c95142eSMartin Matuska 		if (errno == ENOMEM) {
1538fd082e96SMartin Matuska 			free(file);
15396c95142eSMartin Matuska 			archive_set_error(&a->archive, ENOMEM,
15406c95142eSMartin Matuska 			    "Can't allocate memory for UTF-16LE");
15416c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
15426c95142eSMartin Matuska 		}
15436c95142eSMartin Matuska 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
15446c95142eSMartin Matuska 		    "A filename cannot be converted to UTF-16LE;"
15456c95142eSMartin Matuska 		    "You should disable making Joliet extension");
15466c95142eSMartin Matuska 		ret = ARCHIVE_WARN;
15476c95142eSMartin Matuska 	}
15486c95142eSMartin Matuska 	file->utf16name = malloc(u16len + 2);
15496c95142eSMartin Matuska 	if (file->utf16name == NULL) {
1550fd082e96SMartin Matuska 		free(file);
15516c95142eSMartin Matuska 		archive_set_error(&a->archive, ENOMEM,
15526c95142eSMartin Matuska 		    "Can't allocate memory for Name");
15536c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
15546c95142eSMartin Matuska 	}
15556c95142eSMartin Matuska 	memcpy(file->utf16name, u16, u16len);
15566c95142eSMartin Matuska 	file->utf16name[u16len+0] = 0;
15576c95142eSMartin Matuska 	file->utf16name[u16len+1] = 0;
1558acc60b03SMartin Matuska 	file->name_len = (unsigned)u16len;
15596c95142eSMartin Matuska 	file->mode = archive_entry_mode(entry);
15606c95142eSMartin Matuska 	if (archive_entry_filetype(entry) == AE_IFREG)
15616c95142eSMartin Matuska 		file->size = archive_entry_size(entry);
15626c95142eSMartin Matuska 	else
15636c95142eSMartin Matuska 		archive_entry_set_size(entry, 0);
15646c95142eSMartin Matuska 	if (archive_entry_filetype(entry) == AE_IFDIR)
15656c95142eSMartin Matuska 		file->dir = 1;
15666c95142eSMartin Matuska 	else if (archive_entry_filetype(entry) == AE_IFLNK)
15676c95142eSMartin Matuska 		file->size = strlen(archive_entry_symlink(entry));
15686c95142eSMartin Matuska 	if (archive_entry_mtime_is_set(entry)) {
15696c95142eSMartin Matuska 		file->flg |= MTIME_IS_SET;
15706c95142eSMartin Matuska 		file->times[MTIME].time = archive_entry_mtime(entry);
15716c95142eSMartin Matuska 		file->times[MTIME].time_ns = archive_entry_mtime_nsec(entry);
15726c95142eSMartin Matuska 	}
15736c95142eSMartin Matuska 	if (archive_entry_atime_is_set(entry)) {
15746c95142eSMartin Matuska 		file->flg |= ATIME_IS_SET;
15756c95142eSMartin Matuska 		file->times[ATIME].time = archive_entry_atime(entry);
15766c95142eSMartin Matuska 		file->times[ATIME].time_ns = archive_entry_atime_nsec(entry);
15776c95142eSMartin Matuska 	}
15786c95142eSMartin Matuska 	if (archive_entry_ctime_is_set(entry)) {
15796c95142eSMartin Matuska 		file->flg |= CTIME_IS_SET;
15806c95142eSMartin Matuska 		file->times[CTIME].time = archive_entry_ctime(entry);
15816c95142eSMartin Matuska 		file->times[CTIME].time_ns = archive_entry_ctime_nsec(entry);
15826c95142eSMartin Matuska 	}
15836c95142eSMartin Matuska 
15846c95142eSMartin Matuska 	*newfile = file;
15856c95142eSMartin Matuska 	return (ret);
15866c95142eSMartin Matuska }
15876c95142eSMartin Matuska 
15886c95142eSMartin Matuska static void
file_free(struct file * file)15896c95142eSMartin Matuska file_free(struct file *file)
15906c95142eSMartin Matuska {
15916c95142eSMartin Matuska 	free(file->utf16name);
15926c95142eSMartin Matuska 	free(file);
15936c95142eSMartin Matuska }
15946c95142eSMartin Matuska 
15956c95142eSMartin Matuska static void
file_register(struct _7zip * zip,struct file * file)15966c95142eSMartin Matuska file_register(struct _7zip *zip, struct file *file)
15976c95142eSMartin Matuska {
15986c95142eSMartin Matuska 	file->next = NULL;
15996c95142eSMartin Matuska 	*zip->file_list.last = file;
16006c95142eSMartin Matuska 	zip->file_list.last = &(file->next);
16016c95142eSMartin Matuska }
16026c95142eSMartin Matuska 
16036c95142eSMartin Matuska static void
file_init_register(struct _7zip * zip)16046c95142eSMartin Matuska file_init_register(struct _7zip *zip)
16056c95142eSMartin Matuska {
16066c95142eSMartin Matuska 	zip->file_list.first = NULL;
16076c95142eSMartin Matuska 	zip->file_list.last = &(zip->file_list.first);
16086c95142eSMartin Matuska }
16096c95142eSMartin Matuska 
16106c95142eSMartin Matuska static void
file_free_register(struct _7zip * zip)16116c95142eSMartin Matuska file_free_register(struct _7zip *zip)
16126c95142eSMartin Matuska {
16136c95142eSMartin Matuska 	struct file *file, *file_next;
16146c95142eSMartin Matuska 
16156c95142eSMartin Matuska 	file = zip->file_list.first;
16166c95142eSMartin Matuska 	while (file != NULL) {
16176c95142eSMartin Matuska 		file_next = file->next;
16186c95142eSMartin Matuska 		file_free(file);
16196c95142eSMartin Matuska 		file = file_next;
16206c95142eSMartin Matuska 	}
16216c95142eSMartin Matuska }
16226c95142eSMartin Matuska 
16236c95142eSMartin Matuska static void
file_register_empty(struct _7zip * zip,struct file * file)16246c95142eSMartin Matuska file_register_empty(struct _7zip *zip, struct file *file)
16256c95142eSMartin Matuska {
16266c95142eSMartin Matuska 	file->next = NULL;
16276c95142eSMartin Matuska 	*zip->empty_list.last = file;
16286c95142eSMartin Matuska 	zip->empty_list.last = &(file->next);
16296c95142eSMartin Matuska }
16306c95142eSMartin Matuska 
16316c95142eSMartin Matuska static void
file_init_register_empty(struct _7zip * zip)16326c95142eSMartin Matuska file_init_register_empty(struct _7zip *zip)
16336c95142eSMartin Matuska {
16346c95142eSMartin Matuska 	zip->empty_list.first = NULL;
16356c95142eSMartin Matuska 	zip->empty_list.last = &(zip->empty_list.first);
16366c95142eSMartin Matuska }
16376c95142eSMartin Matuska 
16386c95142eSMartin Matuska #if !defined(HAVE_ZLIB_H) || !defined(HAVE_BZLIB_H) ||\
16396c95142eSMartin Matuska 	 !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
16406c95142eSMartin Matuska static int
compression_unsupported_encoder(struct archive * a,struct la_zstream * lastrm,const char * name)16416c95142eSMartin Matuska compression_unsupported_encoder(struct archive *a,
16426c95142eSMartin Matuska     struct la_zstream *lastrm, const char *name)
16436c95142eSMartin Matuska {
16446c95142eSMartin Matuska 
16456c95142eSMartin Matuska 	archive_set_error(a, ARCHIVE_ERRNO_MISC,
16466c95142eSMartin Matuska 	    "%s compression not supported on this platform", name);
16476c95142eSMartin Matuska 	lastrm->valid = 0;
16486c95142eSMartin Matuska 	lastrm->real_stream = NULL;
16496c95142eSMartin Matuska 	return (ARCHIVE_FAILED);
16506c95142eSMartin Matuska }
16516c95142eSMartin Matuska #endif
16526c95142eSMartin Matuska 
16536c95142eSMartin Matuska /*
16546c95142eSMartin Matuska  * _7_COPY compressor.
16556c95142eSMartin Matuska  */
16566c95142eSMartin Matuska static int
compression_init_encoder_copy(struct archive * a,struct la_zstream * lastrm)16576c95142eSMartin Matuska compression_init_encoder_copy(struct archive *a, struct la_zstream *lastrm)
16586c95142eSMartin Matuska {
16596c95142eSMartin Matuska 
16606c95142eSMartin Matuska 	if (lastrm->valid)
16616c95142eSMartin Matuska 		compression_end(a, lastrm);
16626c95142eSMartin Matuska 	lastrm->valid = 1;
16636c95142eSMartin Matuska 	lastrm->code = compression_code_copy;
16646c95142eSMartin Matuska 	lastrm->end = compression_end_copy;
16656c95142eSMartin Matuska 	return (ARCHIVE_OK);
16666c95142eSMartin Matuska }
16676c95142eSMartin Matuska 
16686c95142eSMartin Matuska static int
compression_code_copy(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)16696c95142eSMartin Matuska compression_code_copy(struct archive *a,
16706c95142eSMartin Matuska     struct la_zstream *lastrm, enum la_zaction action)
16716c95142eSMartin Matuska {
16726c95142eSMartin Matuska 	size_t bytes;
16736c95142eSMartin Matuska 
16746c95142eSMartin Matuska 	(void)a; /* UNUSED */
16756c95142eSMartin Matuska 	if (lastrm->avail_out > lastrm->avail_in)
16766c95142eSMartin Matuska 		bytes = lastrm->avail_in;
16776c95142eSMartin Matuska 	else
16786c95142eSMartin Matuska 		bytes = lastrm->avail_out;
16796c95142eSMartin Matuska 	if (bytes) {
16806c95142eSMartin Matuska 		memcpy(lastrm->next_out, lastrm->next_in, bytes);
16816c95142eSMartin Matuska 		lastrm->next_in += bytes;
16826c95142eSMartin Matuska 		lastrm->avail_in -= bytes;
16836c95142eSMartin Matuska 		lastrm->total_in += bytes;
16846c95142eSMartin Matuska 		lastrm->next_out += bytes;
16856c95142eSMartin Matuska 		lastrm->avail_out -= bytes;
16866c95142eSMartin Matuska 		lastrm->total_out += bytes;
16876c95142eSMartin Matuska 	}
16886c95142eSMartin Matuska 	if (action == ARCHIVE_Z_FINISH && lastrm->avail_in == 0)
16896c95142eSMartin Matuska 		return (ARCHIVE_EOF);
16906c95142eSMartin Matuska 	return (ARCHIVE_OK);
16916c95142eSMartin Matuska }
16926c95142eSMartin Matuska 
16936c95142eSMartin Matuska static int
compression_end_copy(struct archive * a,struct la_zstream * lastrm)16946c95142eSMartin Matuska compression_end_copy(struct archive *a, struct la_zstream *lastrm)
16956c95142eSMartin Matuska {
16966c95142eSMartin Matuska 	(void)a; /* UNUSED */
16976c95142eSMartin Matuska 	lastrm->valid = 0;
16986c95142eSMartin Matuska 	return (ARCHIVE_OK);
16996c95142eSMartin Matuska }
17006c95142eSMartin Matuska 
17016c95142eSMartin Matuska /*
17026c95142eSMartin Matuska  * _7_DEFLATE compressor.
17036c95142eSMartin Matuska  */
17046c95142eSMartin Matuska #ifdef HAVE_ZLIB_H
17056c95142eSMartin Matuska static int
compression_init_encoder_deflate(struct archive * a,struct la_zstream * lastrm,int level,int withheader)17066c95142eSMartin Matuska compression_init_encoder_deflate(struct archive *a,
17076c95142eSMartin Matuska     struct la_zstream *lastrm, int level, int withheader)
17086c95142eSMartin Matuska {
17096c95142eSMartin Matuska 	z_stream *strm;
17106c95142eSMartin Matuska 
17116c95142eSMartin Matuska 	if (lastrm->valid)
17126c95142eSMartin Matuska 		compression_end(a, lastrm);
17136c95142eSMartin Matuska 	strm = calloc(1, sizeof(*strm));
17146c95142eSMartin Matuska 	if (strm == NULL) {
17156c95142eSMartin Matuska 		archive_set_error(a, ENOMEM,
17166c95142eSMartin Matuska 		    "Can't allocate memory for gzip stream");
17176c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
17186c95142eSMartin Matuska 	}
17196c95142eSMartin Matuska 	/* zlib.h is not const-correct, so we need this one bit
17206c95142eSMartin Matuska 	 * of ugly hackery to convert a const * pointer to
17216c95142eSMartin Matuska 	 * a non-const pointer. */
17226c95142eSMartin Matuska 	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
1723acc60b03SMartin Matuska 	strm->avail_in = (uInt)lastrm->avail_in;
1724fd082e96SMartin Matuska 	strm->total_in = (uLong)lastrm->total_in;
17256c95142eSMartin Matuska 	strm->next_out = lastrm->next_out;
1726acc60b03SMartin Matuska 	strm->avail_out = (uInt)lastrm->avail_out;
1727fd082e96SMartin Matuska 	strm->total_out = (uLong)lastrm->total_out;
17286c95142eSMartin Matuska 	if (deflateInit2(strm, level, Z_DEFLATED,
17296c95142eSMartin Matuska 	    (withheader)?15:-15,
17306c95142eSMartin Matuska 	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
17316c95142eSMartin Matuska 		free(strm);
17326c95142eSMartin Matuska 		lastrm->real_stream = NULL;
17336c95142eSMartin Matuska 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
17346c95142eSMartin Matuska 		    "Internal error initializing compression library");
17356c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
17366c95142eSMartin Matuska 	}
17376c95142eSMartin Matuska 	lastrm->real_stream = strm;
17386c95142eSMartin Matuska 	lastrm->valid = 1;
17396c95142eSMartin Matuska 	lastrm->code = compression_code_deflate;
17406c95142eSMartin Matuska 	lastrm->end = compression_end_deflate;
17416c95142eSMartin Matuska 	return (ARCHIVE_OK);
17426c95142eSMartin Matuska }
17436c95142eSMartin Matuska 
17446c95142eSMartin Matuska static int
compression_code_deflate(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)17456c95142eSMartin Matuska compression_code_deflate(struct archive *a,
17466c95142eSMartin Matuska     struct la_zstream *lastrm, enum la_zaction action)
17476c95142eSMartin Matuska {
17486c95142eSMartin Matuska 	z_stream *strm;
17496c95142eSMartin Matuska 	int r;
17506c95142eSMartin Matuska 
17516c95142eSMartin Matuska 	strm = (z_stream *)lastrm->real_stream;
17526c95142eSMartin Matuska 	/* zlib.h is not const-correct, so we need this one bit
17536c95142eSMartin Matuska 	 * of ugly hackery to convert a const * pointer to
17546c95142eSMartin Matuska 	 * a non-const pointer. */
17556c95142eSMartin Matuska 	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
1756acc60b03SMartin Matuska 	strm->avail_in = (uInt)lastrm->avail_in;
1757fd082e96SMartin Matuska 	strm->total_in = (uLong)lastrm->total_in;
17586c95142eSMartin Matuska 	strm->next_out = lastrm->next_out;
1759acc60b03SMartin Matuska 	strm->avail_out = (uInt)lastrm->avail_out;
1760fd082e96SMartin Matuska 	strm->total_out = (uLong)lastrm->total_out;
17616c95142eSMartin Matuska 	r = deflate(strm,
17626c95142eSMartin Matuska 	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
17636c95142eSMartin Matuska 	lastrm->next_in = strm->next_in;
17646c95142eSMartin Matuska 	lastrm->avail_in = strm->avail_in;
17656c95142eSMartin Matuska 	lastrm->total_in = strm->total_in;
17666c95142eSMartin Matuska 	lastrm->next_out = strm->next_out;
17676c95142eSMartin Matuska 	lastrm->avail_out = strm->avail_out;
17686c95142eSMartin Matuska 	lastrm->total_out = strm->total_out;
17696c95142eSMartin Matuska 	switch (r) {
17706c95142eSMartin Matuska 	case Z_OK:
17716c95142eSMartin Matuska 		return (ARCHIVE_OK);
17726c95142eSMartin Matuska 	case Z_STREAM_END:
17736c95142eSMartin Matuska 		return (ARCHIVE_EOF);
17746c95142eSMartin Matuska 	default:
17756c95142eSMartin Matuska 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
17766c95142eSMartin Matuska 		    "GZip compression failed:"
17776c95142eSMartin Matuska 		    " deflate() call returned status %d", r);
17786c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
17796c95142eSMartin Matuska 	}
17806c95142eSMartin Matuska }
17816c95142eSMartin Matuska 
17826c95142eSMartin Matuska static int
compression_end_deflate(struct archive * a,struct la_zstream * lastrm)17836c95142eSMartin Matuska compression_end_deflate(struct archive *a, struct la_zstream *lastrm)
17846c95142eSMartin Matuska {
17856c95142eSMartin Matuska 	z_stream *strm;
17866c95142eSMartin Matuska 	int r;
17876c95142eSMartin Matuska 
17886c95142eSMartin Matuska 	strm = (z_stream *)lastrm->real_stream;
17896c95142eSMartin Matuska 	r = deflateEnd(strm);
17906c95142eSMartin Matuska 	free(strm);
17916c95142eSMartin Matuska 	lastrm->real_stream = NULL;
17926c95142eSMartin Matuska 	lastrm->valid = 0;
17936c95142eSMartin Matuska 	if (r != Z_OK) {
17946c95142eSMartin Matuska 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
17956c95142eSMartin Matuska 		    "Failed to clean up compressor");
17966c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
17976c95142eSMartin Matuska 	}
17986c95142eSMartin Matuska 	return (ARCHIVE_OK);
17996c95142eSMartin Matuska }
18006c95142eSMartin Matuska #else
18016c95142eSMartin Matuska static int
compression_init_encoder_deflate(struct archive * a,struct la_zstream * lastrm,int level,int withheader)18026c95142eSMartin Matuska compression_init_encoder_deflate(struct archive *a,
18036c95142eSMartin Matuska     struct la_zstream *lastrm, int level, int withheader)
18046c95142eSMartin Matuska {
18056c95142eSMartin Matuska 
18066c95142eSMartin Matuska 	(void) level; /* UNUSED */
18076c95142eSMartin Matuska 	(void) withheader; /* UNUSED */
18086c95142eSMartin Matuska 	if (lastrm->valid)
18096c95142eSMartin Matuska 		compression_end(a, lastrm);
18106c95142eSMartin Matuska 	return (compression_unsupported_encoder(a, lastrm, "deflate"));
18116c95142eSMartin Matuska }
18126c95142eSMartin Matuska #endif
18136c95142eSMartin Matuska 
18146c95142eSMartin Matuska /*
18156c95142eSMartin Matuska  * _7_BZIP2 compressor.
18166c95142eSMartin Matuska  */
18176c95142eSMartin Matuska #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
18186c95142eSMartin Matuska static int
compression_init_encoder_bzip2(struct archive * a,struct la_zstream * lastrm,int level)18196c95142eSMartin Matuska compression_init_encoder_bzip2(struct archive *a,
18206c95142eSMartin Matuska     struct la_zstream *lastrm, int level)
18216c95142eSMartin Matuska {
18226c95142eSMartin Matuska 	bz_stream *strm;
18236c95142eSMartin Matuska 
18246c95142eSMartin Matuska 	if (lastrm->valid)
18256c95142eSMartin Matuska 		compression_end(a, lastrm);
18266c95142eSMartin Matuska 	strm = calloc(1, sizeof(*strm));
18276c95142eSMartin Matuska 	if (strm == NULL) {
18286c95142eSMartin Matuska 		archive_set_error(a, ENOMEM,
18296c95142eSMartin Matuska 		    "Can't allocate memory for bzip2 stream");
18306c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
18316c95142eSMartin Matuska 	}
18326c95142eSMartin Matuska 	/* bzlib.h is not const-correct, so we need this one bit
18336c95142eSMartin Matuska 	 * of ugly hackery to convert a const * pointer to
18346c95142eSMartin Matuska 	 * a non-const pointer. */
18356c95142eSMartin Matuska 	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
183664884e0dSMartin Matuska 	strm->avail_in = (uint32_t)lastrm->avail_in;
18376c95142eSMartin Matuska 	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
18386c95142eSMartin Matuska 	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
18396c95142eSMartin Matuska 	strm->next_out = (char *)lastrm->next_out;
184064884e0dSMartin Matuska 	strm->avail_out = (uint32_t)lastrm->avail_out;
18416c95142eSMartin Matuska 	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
18426c95142eSMartin Matuska 	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
18436c95142eSMartin Matuska 	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
18446c95142eSMartin Matuska 		free(strm);
18456c95142eSMartin Matuska 		lastrm->real_stream = NULL;
18466c95142eSMartin Matuska 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
18476c95142eSMartin Matuska 		    "Internal error initializing compression library");
18486c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
18496c95142eSMartin Matuska 	}
18506c95142eSMartin Matuska 	lastrm->real_stream = strm;
18516c95142eSMartin Matuska 	lastrm->valid = 1;
18526c95142eSMartin Matuska 	lastrm->code = compression_code_bzip2;
18536c95142eSMartin Matuska 	lastrm->end = compression_end_bzip2;
18546c95142eSMartin Matuska 	return (ARCHIVE_OK);
18556c95142eSMartin Matuska }
18566c95142eSMartin Matuska 
18576c95142eSMartin Matuska static int
compression_code_bzip2(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)18586c95142eSMartin Matuska compression_code_bzip2(struct archive *a,
18596c95142eSMartin Matuska     struct la_zstream *lastrm, enum la_zaction action)
18606c95142eSMartin Matuska {
18616c95142eSMartin Matuska 	bz_stream *strm;
18626c95142eSMartin Matuska 	int r;
18636c95142eSMartin Matuska 
18646c95142eSMartin Matuska 	strm = (bz_stream *)lastrm->real_stream;
18656c95142eSMartin Matuska 	/* bzlib.h is not const-correct, so we need this one bit
18666c95142eSMartin Matuska 	 * of ugly hackery to convert a const * pointer to
18676c95142eSMartin Matuska 	 * a non-const pointer. */
18686c95142eSMartin Matuska 	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
186964884e0dSMartin Matuska 	strm->avail_in = (uint32_t)lastrm->avail_in;
18706c95142eSMartin Matuska 	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
18716c95142eSMartin Matuska 	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
18726c95142eSMartin Matuska 	strm->next_out = (char *)lastrm->next_out;
187364884e0dSMartin Matuska 	strm->avail_out = (uint32_t)lastrm->avail_out;
18746c95142eSMartin Matuska 	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
18756c95142eSMartin Matuska 	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
18766c95142eSMartin Matuska 	r = BZ2_bzCompress(strm,
18776c95142eSMartin Matuska 	    (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
18786c95142eSMartin Matuska 	lastrm->next_in = (const unsigned char *)strm->next_in;
18796c95142eSMartin Matuska 	lastrm->avail_in = strm->avail_in;
18806c95142eSMartin Matuska 	lastrm->total_in =
18816c95142eSMartin Matuska 	    (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
18826c95142eSMartin Matuska 	    + (uint64_t)(uint32_t)strm->total_in_lo32;
18836c95142eSMartin Matuska 	lastrm->next_out = (unsigned char *)strm->next_out;
18846c95142eSMartin Matuska 	lastrm->avail_out = strm->avail_out;
18856c95142eSMartin Matuska 	lastrm->total_out =
18866c95142eSMartin Matuska 	    (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
18876c95142eSMartin Matuska 	    + (uint64_t)(uint32_t)strm->total_out_lo32;
18886c95142eSMartin Matuska 	switch (r) {
18896c95142eSMartin Matuska 	case BZ_RUN_OK:     /* Non-finishing */
18906c95142eSMartin Matuska 	case BZ_FINISH_OK:  /* Finishing: There's more work to do */
18916c95142eSMartin Matuska 		return (ARCHIVE_OK);
18926c95142eSMartin Matuska 	case BZ_STREAM_END: /* Finishing: all done */
18936c95142eSMartin Matuska 		/* Only occurs in finishing case */
18946c95142eSMartin Matuska 		return (ARCHIVE_EOF);
18956c95142eSMartin Matuska 	default:
18966c95142eSMartin Matuska 		/* Any other return value indicates an error */
18976c95142eSMartin Matuska 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
18986c95142eSMartin Matuska 		    "Bzip2 compression failed:"
18996c95142eSMartin Matuska 		    " BZ2_bzCompress() call returned status %d", r);
19006c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
19016c95142eSMartin Matuska 	}
19026c95142eSMartin Matuska }
19036c95142eSMartin Matuska 
19046c95142eSMartin Matuska static int
compression_end_bzip2(struct archive * a,struct la_zstream * lastrm)19056c95142eSMartin Matuska compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
19066c95142eSMartin Matuska {
19076c95142eSMartin Matuska 	bz_stream *strm;
19086c95142eSMartin Matuska 	int r;
19096c95142eSMartin Matuska 
19106c95142eSMartin Matuska 	strm = (bz_stream *)lastrm->real_stream;
19116c95142eSMartin Matuska 	r = BZ2_bzCompressEnd(strm);
19126c95142eSMartin Matuska 	free(strm);
19136c95142eSMartin Matuska 	lastrm->real_stream = NULL;
19146c95142eSMartin Matuska 	lastrm->valid = 0;
19156c95142eSMartin Matuska 	if (r != BZ_OK) {
19166c95142eSMartin Matuska 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
19176c95142eSMartin Matuska 		    "Failed to clean up compressor");
19186c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
19196c95142eSMartin Matuska 	}
19206c95142eSMartin Matuska 	return (ARCHIVE_OK);
19216c95142eSMartin Matuska }
19226c95142eSMartin Matuska 
19236c95142eSMartin Matuska #else
19246c95142eSMartin Matuska static int
compression_init_encoder_bzip2(struct archive * a,struct la_zstream * lastrm,int level)19256c95142eSMartin Matuska compression_init_encoder_bzip2(struct archive *a,
19266c95142eSMartin Matuska     struct la_zstream *lastrm, int level)
19276c95142eSMartin Matuska {
19286c95142eSMartin Matuska 
19296c95142eSMartin Matuska 	(void) level; /* UNUSED */
19306c95142eSMartin Matuska 	if (lastrm->valid)
19316c95142eSMartin Matuska 		compression_end(a, lastrm);
19326c95142eSMartin Matuska 	return (compression_unsupported_encoder(a, lastrm, "bzip2"));
19336c95142eSMartin Matuska }
19346c95142eSMartin Matuska #endif
19356c95142eSMartin Matuska 
19366c95142eSMartin Matuska /*
19376c95142eSMartin Matuska  * _7_LZMA1, _7_LZMA2 compressor.
19386c95142eSMartin Matuska  */
19396c95142eSMartin Matuska #if defined(HAVE_LZMA_H)
19406c95142eSMartin Matuska static int
compression_init_encoder_lzma(struct archive * a,struct la_zstream * lastrm,int level,uint64_t filter_id)19416c95142eSMartin Matuska compression_init_encoder_lzma(struct archive *a,
19426c95142eSMartin Matuska     struct la_zstream *lastrm, int level, uint64_t filter_id)
19436c95142eSMartin Matuska {
19446c95142eSMartin Matuska 	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
19456c95142eSMartin Matuska 	lzma_stream *strm;
19466c95142eSMartin Matuska 	lzma_filter *lzmafilters;
19476c95142eSMartin Matuska 	lzma_options_lzma lzma_opt;
19486c95142eSMartin Matuska 	int r;
19496c95142eSMartin Matuska 
19506c95142eSMartin Matuska 	if (lastrm->valid)
19516c95142eSMartin Matuska 		compression_end(a, lastrm);
19526c95142eSMartin Matuska 	strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
19536c95142eSMartin Matuska 	if (strm == NULL) {
19546c95142eSMartin Matuska 		archive_set_error(a, ENOMEM,
19556c95142eSMartin Matuska 		    "Can't allocate memory for lzma stream");
19566c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
19576c95142eSMartin Matuska 	}
19586c95142eSMartin Matuska 	lzmafilters = (lzma_filter *)(strm+1);
1959c3afd20fSMartin Matuska 	if (level > 9)
1960c3afd20fSMartin Matuska 		level = 9;
19616c95142eSMartin Matuska 	if (lzma_lzma_preset(&lzma_opt, level)) {
1962fd082e96SMartin Matuska 		free(strm);
19636c95142eSMartin Matuska 		lastrm->real_stream = NULL;
19646c95142eSMartin Matuska 		archive_set_error(a, ENOMEM,
19656c95142eSMartin Matuska 		    "Internal error initializing compression library");
19666c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
19676c95142eSMartin Matuska 	}
19686c95142eSMartin Matuska 	lzmafilters[0].id = filter_id;
19696c95142eSMartin Matuska 	lzmafilters[0].options = &lzma_opt;
19706c95142eSMartin Matuska 	lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
19716c95142eSMartin Matuska 
19726c95142eSMartin Matuska 	r = lzma_properties_size(&(lastrm->prop_size), lzmafilters);
19736c95142eSMartin Matuska 	if (r != LZMA_OK) {
19746c95142eSMartin Matuska 		free(strm);
19756c95142eSMartin Matuska 		lastrm->real_stream = NULL;
19766c95142eSMartin Matuska 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
19776c95142eSMartin Matuska 		    "lzma_properties_size failed");
19786c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
19796c95142eSMartin Matuska 	}
19806c95142eSMartin Matuska 	if (lastrm->prop_size) {
19816c95142eSMartin Matuska 		lastrm->props = malloc(lastrm->prop_size);
19826c95142eSMartin Matuska 		if (lastrm->props == NULL) {
19836c95142eSMartin Matuska 			free(strm);
19846c95142eSMartin Matuska 			lastrm->real_stream = NULL;
19856c95142eSMartin Matuska 			archive_set_error(a, ENOMEM,
19866c95142eSMartin Matuska 			    "Cannot allocate memory");
19876c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
19886c95142eSMartin Matuska 		}
19896c95142eSMartin Matuska 		r = lzma_properties_encode(lzmafilters,  lastrm->props);
19906c95142eSMartin Matuska 		if (r != LZMA_OK) {
19916c95142eSMartin Matuska 			free(strm);
19926c95142eSMartin Matuska 			lastrm->real_stream = NULL;
19936c95142eSMartin Matuska 			archive_set_error(a, ARCHIVE_ERRNO_MISC,
19946c95142eSMartin Matuska 			    "lzma_properties_encode failed");
19956c95142eSMartin Matuska 			return (ARCHIVE_FATAL);
19966c95142eSMartin Matuska 		}
19976c95142eSMartin Matuska 	}
19986c95142eSMartin Matuska 
19996c95142eSMartin Matuska 	*strm = lzma_init_data;
20006c95142eSMartin Matuska 	r = lzma_raw_encoder(strm, lzmafilters);
20016c95142eSMartin Matuska 	switch (r) {
20026c95142eSMartin Matuska 	case LZMA_OK:
20036c95142eSMartin Matuska 		lastrm->real_stream = strm;
20046c95142eSMartin Matuska 		lastrm->valid = 1;
20056c95142eSMartin Matuska 		lastrm->code = compression_code_lzma;
20066c95142eSMartin Matuska 		lastrm->end = compression_end_lzma;
20076c95142eSMartin Matuska 		r = ARCHIVE_OK;
20086c95142eSMartin Matuska 		break;
20096c95142eSMartin Matuska 	case LZMA_MEM_ERROR:
20106c95142eSMartin Matuska 		free(strm);
20116c95142eSMartin Matuska 		lastrm->real_stream = NULL;
20126c95142eSMartin Matuska 		archive_set_error(a, ENOMEM,
20136c95142eSMartin Matuska 		    "Internal error initializing compression library: "
20146c95142eSMartin Matuska 		    "Cannot allocate memory");
20156c95142eSMartin Matuska 		r =  ARCHIVE_FATAL;
20166c95142eSMartin Matuska 		break;
20176c95142eSMartin Matuska         default:
20186c95142eSMartin Matuska 		free(strm);
20196c95142eSMartin Matuska 		lastrm->real_stream = NULL;
20206c95142eSMartin Matuska 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
20216c95142eSMartin Matuska 		    "Internal error initializing compression library: "
20226c95142eSMartin Matuska 		    "It's a bug in liblzma");
20236c95142eSMartin Matuska 		r =  ARCHIVE_FATAL;
20246c95142eSMartin Matuska 		break;
20256c95142eSMartin Matuska 	}
20266c95142eSMartin Matuska 	return (r);
20276c95142eSMartin Matuska }
20286c95142eSMartin Matuska 
20296c95142eSMartin Matuska static int
compression_init_encoder_lzma1(struct archive * a,struct la_zstream * lastrm,int level)20306c95142eSMartin Matuska compression_init_encoder_lzma1(struct archive *a,
20316c95142eSMartin Matuska     struct la_zstream *lastrm, int level)
20326c95142eSMartin Matuska {
20336c95142eSMartin Matuska 	return compression_init_encoder_lzma(a, lastrm, level,
20346c95142eSMartin Matuska 		    LZMA_FILTER_LZMA1);
20356c95142eSMartin Matuska }
20366c95142eSMartin Matuska 
20376c95142eSMartin Matuska static int
compression_init_encoder_lzma2(struct archive * a,struct la_zstream * lastrm,int level)20386c95142eSMartin Matuska compression_init_encoder_lzma2(struct archive *a,
20396c95142eSMartin Matuska     struct la_zstream *lastrm, int level)
20406c95142eSMartin Matuska {
20416c95142eSMartin Matuska 	return compression_init_encoder_lzma(a, lastrm, level,
20426c95142eSMartin Matuska 		    LZMA_FILTER_LZMA2);
20436c95142eSMartin Matuska }
20446c95142eSMartin Matuska 
20456c95142eSMartin Matuska static int
compression_code_lzma(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)20466c95142eSMartin Matuska compression_code_lzma(struct archive *a,
20476c95142eSMartin Matuska     struct la_zstream *lastrm, enum la_zaction action)
20486c95142eSMartin Matuska {
20496c95142eSMartin Matuska 	lzma_stream *strm;
20506c95142eSMartin Matuska 	int r;
20516c95142eSMartin Matuska 
20526c95142eSMartin Matuska 	strm = (lzma_stream *)lastrm->real_stream;
20536c95142eSMartin Matuska 	strm->next_in = lastrm->next_in;
20546c95142eSMartin Matuska 	strm->avail_in = lastrm->avail_in;
20556c95142eSMartin Matuska 	strm->total_in = lastrm->total_in;
20566c95142eSMartin Matuska 	strm->next_out = lastrm->next_out;
20576c95142eSMartin Matuska 	strm->avail_out = lastrm->avail_out;
20586c95142eSMartin Matuska 	strm->total_out = lastrm->total_out;
20596c95142eSMartin Matuska 	r = lzma_code(strm,
20606c95142eSMartin Matuska 	    (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
20616c95142eSMartin Matuska 	lastrm->next_in = strm->next_in;
20626c95142eSMartin Matuska 	lastrm->avail_in = strm->avail_in;
20636c95142eSMartin Matuska 	lastrm->total_in = strm->total_in;
20646c95142eSMartin Matuska 	lastrm->next_out = strm->next_out;
20656c95142eSMartin Matuska 	lastrm->avail_out = strm->avail_out;
20666c95142eSMartin Matuska 	lastrm->total_out = strm->total_out;
20676c95142eSMartin Matuska 	switch (r) {
20686c95142eSMartin Matuska 	case LZMA_OK:
20696c95142eSMartin Matuska 		/* Non-finishing case */
20706c95142eSMartin Matuska 		return (ARCHIVE_OK);
20716c95142eSMartin Matuska 	case LZMA_STREAM_END:
20726c95142eSMartin Matuska 		/* This return can only occur in finishing case. */
20736c95142eSMartin Matuska 		return (ARCHIVE_EOF);
20746c95142eSMartin Matuska 	case LZMA_MEMLIMIT_ERROR:
20756c95142eSMartin Matuska 		archive_set_error(a, ENOMEM,
20766c95142eSMartin Matuska 		    "lzma compression error:"
20776c95142eSMartin Matuska 		    " %ju MiB would have been needed",
20786c95142eSMartin Matuska 		    (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
20796c95142eSMartin Matuska 			/ (1024 * 1024)));
20806c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
20816c95142eSMartin Matuska 	default:
20826c95142eSMartin Matuska 		/* Any other return value indicates an error */
20836c95142eSMartin Matuska 		archive_set_error(a, ARCHIVE_ERRNO_MISC,
20846c95142eSMartin Matuska 		    "lzma compression failed:"
20856c95142eSMartin Matuska 		    " lzma_code() call returned status %d", r);
20866c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
20876c95142eSMartin Matuska 	}
20886c95142eSMartin Matuska }
20896c95142eSMartin Matuska 
20906c95142eSMartin Matuska static int
compression_end_lzma(struct archive * a,struct la_zstream * lastrm)20916c95142eSMartin Matuska compression_end_lzma(struct archive *a, struct la_zstream *lastrm)
20926c95142eSMartin Matuska {
20936c95142eSMartin Matuska 	lzma_stream *strm;
20946c95142eSMartin Matuska 
20956c95142eSMartin Matuska 	(void)a; /* UNUSED */
20966c95142eSMartin Matuska 	strm = (lzma_stream *)lastrm->real_stream;
20976c95142eSMartin Matuska 	lzma_end(strm);
20986c95142eSMartin Matuska 	free(strm);
20996c95142eSMartin Matuska 	lastrm->valid = 0;
21006c95142eSMartin Matuska 	lastrm->real_stream = NULL;
21016c95142eSMartin Matuska 	return (ARCHIVE_OK);
21026c95142eSMartin Matuska }
21036c95142eSMartin Matuska #else
21046c95142eSMartin Matuska static int
compression_init_encoder_lzma1(struct archive * a,struct la_zstream * lastrm,int level)21056c95142eSMartin Matuska compression_init_encoder_lzma1(struct archive *a,
21066c95142eSMartin Matuska     struct la_zstream *lastrm, int level)
21076c95142eSMartin Matuska {
21086c95142eSMartin Matuska 
21096c95142eSMartin Matuska 	(void) level; /* UNUSED */
21106c95142eSMartin Matuska 	if (lastrm->valid)
21116c95142eSMartin Matuska 		compression_end(a, lastrm);
21126c95142eSMartin Matuska 	return (compression_unsupported_encoder(a, lastrm, "lzma"));
21136c95142eSMartin Matuska }
21146c95142eSMartin Matuska static int
compression_init_encoder_lzma2(struct archive * a,struct la_zstream * lastrm,int level)21156c95142eSMartin Matuska compression_init_encoder_lzma2(struct archive *a,
21166c95142eSMartin Matuska     struct la_zstream *lastrm, int level)
21176c95142eSMartin Matuska {
21186c95142eSMartin Matuska 
21196c95142eSMartin Matuska 	(void) level; /* UNUSED */
21206c95142eSMartin Matuska 	if (lastrm->valid)
21216c95142eSMartin Matuska 		compression_end(a, lastrm);
21226c95142eSMartin Matuska 	return (compression_unsupported_encoder(a, lastrm, "lzma"));
21236c95142eSMartin Matuska }
21246c95142eSMartin Matuska #endif
21256c95142eSMartin Matuska 
21266c95142eSMartin Matuska /*
21276c95142eSMartin Matuska  * _7_PPMD compressor.
21286c95142eSMartin Matuska  */
21296c95142eSMartin Matuska static void
ppmd_write(void * p,Byte b)21306c95142eSMartin Matuska ppmd_write(void *p, Byte b)
21316c95142eSMartin Matuska {
21326c95142eSMartin Matuska 	struct archive_write *a = ((IByteOut *)p)->a;
21336c95142eSMartin Matuska 	struct _7zip *zip = (struct _7zip *)(a->format_data);
21346c95142eSMartin Matuska 	struct la_zstream *lastrm = &(zip->stream);
21356c95142eSMartin Matuska 	struct ppmd_stream *strm;
21366c95142eSMartin Matuska 
21376c95142eSMartin Matuska 	if (lastrm->avail_out) {
21386c95142eSMartin Matuska 		*lastrm->next_out++ = b;
21396c95142eSMartin Matuska 		lastrm->avail_out--;
21406c95142eSMartin Matuska 		lastrm->total_out++;
21416c95142eSMartin Matuska 		return;
21426c95142eSMartin Matuska 	}
21436c95142eSMartin Matuska 	strm = (struct ppmd_stream *)lastrm->real_stream;
21446c95142eSMartin Matuska 	if (strm->buff_ptr < strm->buff_end) {
21456c95142eSMartin Matuska 		*strm->buff_ptr++ = b;
21466c95142eSMartin Matuska 		strm->buff_bytes++;
21476c95142eSMartin Matuska 	}
21486c95142eSMartin Matuska }
21496c95142eSMartin Matuska 
21506c95142eSMartin Matuska static int
compression_init_encoder_ppmd(struct archive * a,struct la_zstream * lastrm,unsigned maxOrder,uint32_t msize)21516c95142eSMartin Matuska compression_init_encoder_ppmd(struct archive *a,
21526c95142eSMartin Matuska     struct la_zstream *lastrm, unsigned maxOrder, uint32_t msize)
21536c95142eSMartin Matuska {
21546c95142eSMartin Matuska 	struct ppmd_stream *strm;
21556c95142eSMartin Matuska 	uint8_t *props;
21566c95142eSMartin Matuska 	int r;
21576c95142eSMartin Matuska 
21586c95142eSMartin Matuska 	if (lastrm->valid)
21596c95142eSMartin Matuska 		compression_end(a, lastrm);
21606c95142eSMartin Matuska 	strm = calloc(1, sizeof(*strm));
21616c95142eSMartin Matuska 	if (strm == NULL) {
21626c95142eSMartin Matuska 		archive_set_error(a, ENOMEM,
21636c95142eSMartin Matuska 		    "Can't allocate memory for PPMd");
21646c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
21656c95142eSMartin Matuska 	}
21666c95142eSMartin Matuska 	strm->buff = malloc(32);
21676c95142eSMartin Matuska 	if (strm->buff == NULL) {
21686c95142eSMartin Matuska 		free(strm);
21696c95142eSMartin Matuska 		archive_set_error(a, ENOMEM,
21706c95142eSMartin Matuska 		    "Can't allocate memory for PPMd");
21716c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
21726c95142eSMartin Matuska 	}
21736c95142eSMartin Matuska 	strm->buff_ptr = strm->buff;
21746c95142eSMartin Matuska 	strm->buff_end = strm->buff + 32;
21756c95142eSMartin Matuska 
21766c95142eSMartin Matuska 	props = malloc(1+4);
21776c95142eSMartin Matuska 	if (props == NULL) {
21786c95142eSMartin Matuska 		free(strm->buff);
21796c95142eSMartin Matuska 		free(strm);
21806c95142eSMartin Matuska 		archive_set_error(a, ENOMEM,
21816c95142eSMartin Matuska 		    "Coludn't allocate memory for PPMd");
21826c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
21836c95142eSMartin Matuska 	}
21846c95142eSMartin Matuska 	props[0] = maxOrder;
21856c95142eSMartin Matuska 	archive_le32enc(props+1, msize);
21866c95142eSMartin Matuska 	__archive_ppmd7_functions.Ppmd7_Construct(&strm->ppmd7_context);
21876c95142eSMartin Matuska 	r = __archive_ppmd7_functions.Ppmd7_Alloc(
2188a2a3407cSMartin Matuska 		&strm->ppmd7_context, msize);
21896c95142eSMartin Matuska 	if (r == 0) {
21906c95142eSMartin Matuska 		free(strm->buff);
21916c95142eSMartin Matuska 		free(strm);
21926c95142eSMartin Matuska 		free(props);
21936c95142eSMartin Matuska 		archive_set_error(a, ENOMEM,
21946c95142eSMartin Matuska 		    "Coludn't allocate memory for PPMd");
21956c95142eSMartin Matuska 		return (ARCHIVE_FATAL);
21966c95142eSMartin Matuska 	}
21976c95142eSMartin Matuska 	__archive_ppmd7_functions.Ppmd7_Init(&(strm->ppmd7_context), maxOrder);
21986c95142eSMartin Matuska 	strm->byteout.a = (struct archive_write *)a;
21996c95142eSMartin Matuska 	strm->byteout.Write = ppmd_write;
22006c95142eSMartin Matuska 	strm->range_enc.Stream = &(strm->byteout);
22016c95142eSMartin Matuska 	__archive_ppmd7_functions.Ppmd7z_RangeEnc_Init(&(strm->range_enc));
22026c95142eSMartin Matuska 	strm->stat = 0;
22036c95142eSMartin Matuska 
22046c95142eSMartin Matuska 	lastrm->real_stream = strm;
22056c95142eSMartin Matuska 	lastrm->valid = 1;
22066c95142eSMartin Matuska 	lastrm->code = compression_code_ppmd;
22076c95142eSMartin Matuska 	lastrm->end = compression_end_ppmd;
22086c95142eSMartin Matuska 	lastrm->prop_size = 5;
22096c95142eSMartin Matuska 	lastrm->props = props;
22106c95142eSMartin Matuska 	return (ARCHIVE_OK);
22116c95142eSMartin Matuska }
22126c95142eSMartin Matuska 
22136c95142eSMartin Matuska static int
compression_code_ppmd(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)22146c95142eSMartin Matuska compression_code_ppmd(struct archive *a,
22156c95142eSMartin Matuska     struct la_zstream *lastrm, enum la_zaction action)
22166c95142eSMartin Matuska {
22176c95142eSMartin Matuska 	struct ppmd_stream *strm;
22186c95142eSMartin Matuska 
22196c95142eSMartin Matuska 	(void)a; /* UNUSED */
22206c95142eSMartin Matuska 
22216c95142eSMartin Matuska 	strm = (struct ppmd_stream *)lastrm->real_stream;
22226c95142eSMartin Matuska 
22236c95142eSMartin Matuska 	/* Copy encoded data if there are remaining bytes from previous call. */
22246c95142eSMartin Matuska 	if (strm->buff_bytes) {
22256c95142eSMartin Matuska 		uint8_t *p = strm->buff_ptr - strm->buff_bytes;
22266c95142eSMartin Matuska 		while (lastrm->avail_out && strm->buff_bytes) {
22276c95142eSMartin Matuska 			*lastrm->next_out++ = *p++;
22286c95142eSMartin Matuska 			lastrm->avail_out--;
22296c95142eSMartin Matuska 			lastrm->total_out++;
22306c95142eSMartin Matuska 			strm->buff_bytes--;
22316c95142eSMartin Matuska 		}
22326c95142eSMartin Matuska 		if (strm->buff_bytes)
22336c95142eSMartin Matuska 			return (ARCHIVE_OK);
22346c95142eSMartin Matuska 		if (strm->stat == 1)
22356c95142eSMartin Matuska 			return (ARCHIVE_EOF);
22366c95142eSMartin Matuska 		strm->buff_ptr = strm->buff;
22376c95142eSMartin Matuska 	}
22386c95142eSMartin Matuska 	while (lastrm->avail_in && lastrm->avail_out) {
22396c95142eSMartin Matuska 		__archive_ppmd7_functions.Ppmd7_EncodeSymbol(
22406c95142eSMartin Matuska 			&(strm->ppmd7_context), &(strm->range_enc),
22416c95142eSMartin Matuska 			*lastrm->next_in++);
22426c95142eSMartin Matuska 		lastrm->avail_in--;
22436c95142eSMartin Matuska 		lastrm->total_in++;
22446c95142eSMartin Matuska 	}
22456c95142eSMartin Matuska 	if (lastrm->avail_in == 0 && action == ARCHIVE_Z_FINISH) {
22466c95142eSMartin Matuska 		__archive_ppmd7_functions.Ppmd7z_RangeEnc_FlushData(
22476c95142eSMartin Matuska 			&(strm->range_enc));
22486c95142eSMartin Matuska 		strm->stat = 1;
22496c95142eSMartin Matuska 		/* Return EOF if there are no remaining bytes. */
22506c95142eSMartin Matuska 		if (strm->buff_bytes == 0)
22516c95142eSMartin Matuska 			return (ARCHIVE_EOF);
22526c95142eSMartin Matuska 	}
22536c95142eSMartin Matuska 	return (ARCHIVE_OK);
22546c95142eSMartin Matuska }
22556c95142eSMartin Matuska 
22566c95142eSMartin Matuska static int
compression_end_ppmd(struct archive * a,struct la_zstream * lastrm)22576c95142eSMartin Matuska compression_end_ppmd(struct archive *a, struct la_zstream *lastrm)
22586c95142eSMartin Matuska {
22596c95142eSMartin Matuska 	struct ppmd_stream *strm;
22606c95142eSMartin Matuska 
22616c95142eSMartin Matuska 	(void)a; /* UNUSED */
22626c95142eSMartin Matuska 
22636c95142eSMartin Matuska 	strm = (struct ppmd_stream *)lastrm->real_stream;
2264a2a3407cSMartin Matuska 	__archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context);
22656c95142eSMartin Matuska 	free(strm->buff);
22666c95142eSMartin Matuska 	free(strm);
22676c95142eSMartin Matuska 	lastrm->real_stream = NULL;
22686c95142eSMartin Matuska 	lastrm->valid = 0;
22696c95142eSMartin Matuska 	return (ARCHIVE_OK);
22706c95142eSMartin Matuska }
22716c95142eSMartin Matuska 
22726c95142eSMartin Matuska /*
22736c95142eSMartin Matuska  * Universal compressor initializer.
22746c95142eSMartin Matuska  */
22756c95142eSMartin Matuska static int
_7z_compression_init_encoder(struct archive_write * a,unsigned compression,int compression_level)22766c95142eSMartin Matuska _7z_compression_init_encoder(struct archive_write *a, unsigned compression,
22776c95142eSMartin Matuska     int compression_level)
22786c95142eSMartin Matuska {
22796c95142eSMartin Matuska 	struct _7zip *zip;
22806c95142eSMartin Matuska 	int r;
22816c95142eSMartin Matuska 
22826c95142eSMartin Matuska 	zip = (struct _7zip *)a->format_data;
22836c95142eSMartin Matuska 	switch (compression) {
22846c95142eSMartin Matuska 	case _7Z_DEFLATE:
22856c95142eSMartin Matuska 		r = compression_init_encoder_deflate(
22866c95142eSMartin Matuska 		    &(a->archive), &(zip->stream),
22876c95142eSMartin Matuska 		    compression_level, 0);
22886c95142eSMartin Matuska 		break;
22896c95142eSMartin Matuska 	case _7Z_BZIP2:
22906c95142eSMartin Matuska 		r = compression_init_encoder_bzip2(
22916c95142eSMartin Matuska 		    &(a->archive), &(zip->stream),
22926c95142eSMartin Matuska 		    compression_level);
22936c95142eSMartin Matuska 		break;
22946c95142eSMartin Matuska 	case _7Z_LZMA1:
22956c95142eSMartin Matuska 		r = compression_init_encoder_lzma1(
22966c95142eSMartin Matuska 		    &(a->archive), &(zip->stream),
22976c95142eSMartin Matuska 		    compression_level);
22986c95142eSMartin Matuska 		break;
22996c95142eSMartin Matuska 	case _7Z_LZMA2:
23006c95142eSMartin Matuska 		r = compression_init_encoder_lzma2(
23016c95142eSMartin Matuska 		    &(a->archive), &(zip->stream),
23026c95142eSMartin Matuska 		    compression_level);
23036c95142eSMartin Matuska 		break;
23046c95142eSMartin Matuska 	case _7Z_PPMD:
23056c95142eSMartin Matuska 		r = compression_init_encoder_ppmd(
23066c95142eSMartin Matuska 		    &(a->archive), &(zip->stream),
23076c95142eSMartin Matuska 		    PPMD7_DEFAULT_ORDER, PPMD7_DEFAULT_MEM_SIZE);
23086c95142eSMartin Matuska 		break;
23096c95142eSMartin Matuska 	case _7Z_COPY:
23106c95142eSMartin Matuska 	default:
23116c95142eSMartin Matuska 		r = compression_init_encoder_copy(
23126c95142eSMartin Matuska 		    &(a->archive), &(zip->stream));
23136c95142eSMartin Matuska 		break;
23146c95142eSMartin Matuska 	}
23156c95142eSMartin Matuska 	if (r == ARCHIVE_OK) {
23166c95142eSMartin Matuska 		zip->stream.total_in = 0;
23176c95142eSMartin Matuska 		zip->stream.next_out = zip->wbuff;
23186c95142eSMartin Matuska 		zip->stream.avail_out = sizeof(zip->wbuff);
23196c95142eSMartin Matuska 		zip->stream.total_out = 0;
23206c95142eSMartin Matuska 	}
23216c95142eSMartin Matuska 
23226c95142eSMartin Matuska 	return (r);
23236c95142eSMartin Matuska }
23246c95142eSMartin Matuska 
23256c95142eSMartin Matuska static int
compression_code(struct archive * a,struct la_zstream * lastrm,enum la_zaction action)23266c95142eSMartin Matuska compression_code(struct archive *a, struct la_zstream *lastrm,
23276c95142eSMartin Matuska     enum la_zaction action)
23286c95142eSMartin Matuska {
23296c95142eSMartin Matuska 	if (lastrm->valid)
23306c95142eSMartin Matuska 		return (lastrm->code(a, lastrm, action));
23316c95142eSMartin Matuska 	return (ARCHIVE_OK);
23326c95142eSMartin Matuska }
23336c95142eSMartin Matuska 
23346c95142eSMartin Matuska static int
compression_end(struct archive * a,struct la_zstream * lastrm)23356c95142eSMartin Matuska compression_end(struct archive *a, struct la_zstream *lastrm)
23366c95142eSMartin Matuska {
23376c95142eSMartin Matuska 	if (lastrm->valid) {
23386c95142eSMartin Matuska 		lastrm->prop_size = 0;
23396c95142eSMartin Matuska 		free(lastrm->props);
23406c95142eSMartin Matuska 		lastrm->props = NULL;
23416c95142eSMartin Matuska 		return (lastrm->end(a, lastrm));
23426c95142eSMartin Matuska 	}
23436c95142eSMartin Matuska 	return (ARCHIVE_OK);
23446c95142eSMartin Matuska }
23456c95142eSMartin Matuska 
23466c95142eSMartin Matuska 
2347