archive_write_set_format_7zip.c revision 231200
1231200Smm/*-
2231200Smm * Copyright (c) 2011-2012 Michihiro NAKAJIMA
3231200Smm * All rights reserved.
4231200Smm *
5231200Smm * Redistribution and use in source and binary forms, with or without
6231200Smm * modification, are permitted provided that the following conditions
7231200Smm * are met:
8231200Smm * 1. Redistributions of source code must retain the above copyright
9231200Smm *    notice, this list of conditions and the following disclaimer.
10231200Smm * 2. Redistributions in binary form must reproduce the above copyright
11231200Smm *    notice, this list of conditions and the following disclaimer in the
12231200Smm *    documentation and/or other materials provided with the distribution.
13231200Smm *
14231200Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15231200Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16231200Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17231200Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18231200Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19231200Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20231200Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21231200Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22231200Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23231200Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24231200Smm */
25231200Smm
26231200Smm#include "archive_platform.h"
27231200Smm__FBSDID("$FreeBSD$");
28231200Smm
29231200Smm#ifdef HAVE_ERRNO_H
30231200Smm#include <errno.h>
31231200Smm#endif
32231200Smm#include <stdlib.h>
33231200Smm#ifdef HAVE_BZLIB_H
34231200Smm#include <bzlib.h>
35231200Smm#endif
36231200Smm#if HAVE_LZMA_H
37231200Smm#include <lzma.h>
38231200Smm#endif
39231200Smm#ifdef HAVE_ZLIB_H
40231200Smm#include <zlib.h>
41231200Smm#endif
42231200Smm
43231200Smm#include "archive.h"
44231200Smm#ifndef HAVE_ZLIB_H
45231200Smm#include "archive_crc32.h"
46231200Smm#endif
47231200Smm#include "archive_endian.h"
48231200Smm#include "archive_entry.h"
49231200Smm#include "archive_entry_locale.h"
50231200Smm#include "archive_ppmd7_private.h"
51231200Smm#include "archive_private.h"
52231200Smm#include "archive_rb.h"
53231200Smm#include "archive_string.h"
54231200Smm#include "archive_write_private.h"
55231200Smm
56231200Smm/*
57231200Smm * Codec ID
58231200Smm */
59231200Smm#define _7Z_COPY	0
60231200Smm#define _7Z_LZMA1	0x030101
61231200Smm#define _7Z_LZMA2	0x21
62231200Smm#define _7Z_DEFLATE	0x040108
63231200Smm#define _7Z_BZIP2	0x040202
64231200Smm#define _7Z_PPMD	0x030401
65231200Smm
66231200Smm/*
67231200Smm * 7-Zip header property IDs.
68231200Smm */
69231200Smm#define kEnd			0x00
70231200Smm#define kHeader			0x01
71231200Smm#define kArchiveProperties	0x02
72231200Smm#define kAdditionalStreamsInfo	0x03
73231200Smm#define kMainStreamsInfo	0x04
74231200Smm#define kFilesInfo		0x05
75231200Smm#define kPackInfo		0x06
76231200Smm#define kUnPackInfo		0x07
77231200Smm#define kSubStreamsInfo		0x08
78231200Smm#define kSize			0x09
79231200Smm#define kCRC			0x0A
80231200Smm#define kFolder			0x0B
81231200Smm#define kCodersUnPackSize	0x0C
82231200Smm#define kNumUnPackStream	0x0D
83231200Smm#define kEmptyStream		0x0E
84231200Smm#define kEmptyFile		0x0F
85231200Smm#define kAnti			0x10
86231200Smm#define kName			0x11
87231200Smm#define kCTime			0x12
88231200Smm#define kATime			0x13
89231200Smm#define kMTime			0x14
90231200Smm#define kAttributes		0x15
91231200Smm#define kEncodedHeader		0x17
92231200Smm
93231200Smmenum la_zaction {
94231200Smm	ARCHIVE_Z_FINISH,
95231200Smm	ARCHIVE_Z_RUN
96231200Smm};
97231200Smm
98231200Smm/*
99231200Smm * A stream object of universal compressor.
100231200Smm */
101231200Smmstruct la_zstream {
102231200Smm	const uint8_t		*next_in;
103231200Smm	size_t			 avail_in;
104231200Smm	uint64_t		 total_in;
105231200Smm
106231200Smm	uint8_t			*next_out;
107231200Smm	size_t			 avail_out;
108231200Smm	uint64_t		 total_out;
109231200Smm
110231200Smm	uint32_t		 prop_size;
111231200Smm	uint8_t			*props;
112231200Smm
113231200Smm	int			 valid;
114231200Smm	void			*real_stream;
115231200Smm	int			 (*code) (struct archive *a,
116231200Smm				    struct la_zstream *lastrm,
117231200Smm				    enum la_zaction action);
118231200Smm	int			 (*end)(struct archive *a,
119231200Smm				    struct la_zstream *lastrm);
120231200Smm};
121231200Smm
122231200Smm#define PPMD7_DEFAULT_ORDER	6
123231200Smm#define PPMD7_DEFAULT_MEM_SIZE	(1 << 24)
124231200Smm
125231200Smmstruct ppmd_stream {
126231200Smm	int			 stat;
127231200Smm	CPpmd7			 ppmd7_context;
128231200Smm	CPpmd7z_RangeEnc	 range_enc;
129231200Smm	IByteOut		 byteout;
130231200Smm	uint8_t			*buff;
131231200Smm	uint8_t			*buff_ptr;
132231200Smm	uint8_t			*buff_end;
133231200Smm	size_t			 buff_bytes;
134231200Smm};
135231200Smm
136231200Smmstruct coder {
137231200Smm	unsigned		 codec;
138231200Smm	size_t			 prop_size;
139231200Smm	uint8_t			*props;
140231200Smm};
141231200Smm
142231200Smmstruct file {
143231200Smm	struct archive_rb_node	 rbnode;
144231200Smm
145231200Smm	struct file		*next;
146231200Smm	unsigned		 name_len;
147231200Smm	uint8_t			*utf16name;/* UTF16-LE name. */
148231200Smm	uint64_t		 size;
149231200Smm	unsigned		 flg;
150231200Smm#define MTIME_IS_SET	(1<<0)
151231200Smm#define ATIME_IS_SET	(1<<1)
152231200Smm#define CTIME_IS_SET	(1<<2)
153231200Smm#define CRC32_IS_SET	(1<<3)
154231200Smm#define HAS_STREAM	(1<<4)
155231200Smm
156231200Smm	struct {
157231200Smm		time_t		 time;
158231200Smm		long		 time_ns;
159231200Smm	}			 times[3];
160231200Smm#define MTIME 0
161231200Smm#define ATIME 1
162231200Smm#define CTIME 2
163231200Smm
164231200Smm	mode_t			 mode;
165231200Smm	uint32_t		 crc32;
166231200Smm
167231200Smm	int			 dir:1;
168231200Smm};
169231200Smm
170231200Smmstruct _7zip {
171231200Smm	int			 temp_fd;
172231200Smm	uint64_t		 temp_offset;
173231200Smm
174231200Smm	struct file		*cur_file;
175231200Smm	size_t			 total_number_entry;
176231200Smm	size_t			 total_number_nonempty_entry;
177231200Smm	size_t			 total_number_empty_entry;
178231200Smm	size_t			 total_number_dir_entry;
179231200Smm	size_t			 total_bytes_entry_name;
180231200Smm	size_t			 total_number_time_defined[3];
181231200Smm	uint64_t		 total_bytes_compressed;
182231200Smm	uint64_t		 total_bytes_uncompressed;
183231200Smm	uint64_t		 entry_bytes_remaining;
184231200Smm	uint32_t		 entry_crc32;
185231200Smm	uint32_t		 precode_crc32;
186231200Smm	uint32_t		 encoded_crc32;
187231200Smm	int			 crc32flg;
188231200Smm#define	PRECODE_CRC32	1
189231200Smm#define	ENCODED_CRC32	2
190231200Smm
191231200Smm	unsigned		 opt_compression;
192231200Smm	int			 opt_compression_level;
193231200Smm
194231200Smm	struct la_zstream	 stream;
195231200Smm	struct coder		 coder;
196231200Smm
197231200Smm	struct archive_string_conv *sconv;
198231200Smm
199231200Smm	/*
200231200Smm	 * Compressed data buffer.
201231200Smm	 */
202231200Smm	unsigned char		 wbuff[1024 * 64];
203231200Smm	size_t			 wbuff_remaining;
204231200Smm
205231200Smm	/*
206231200Smm	 * The list of the file entries which has its contents is used to
207231200Smm	 * manage struct file objects.
208231200Smm	 * We use 'next' a menber of struct file to chain.
209231200Smm	 */
210231200Smm	struct {
211231200Smm		struct file	*first;
212231200Smm		struct file	**last;
213231200Smm	}			 file_list, empty_list;
214231200Smm	struct archive_rb_tree	 rbtree;/* for empty files */
215231200Smm};
216231200Smm
217231200Smmstatic int	_7z_options(struct archive_write *,
218231200Smm		    const char *, const char *);
219231200Smmstatic int	_7z_write_header(struct archive_write *,
220231200Smm		    struct archive_entry *);
221231200Smmstatic ssize_t	_7z_write_data(struct archive_write *,
222231200Smm		    const void *, size_t);
223231200Smmstatic int	_7z_finish_entry(struct archive_write *);
224231200Smmstatic int	_7z_close(struct archive_write *);
225231200Smmstatic int	_7z_free(struct archive_write *);
226231200Smmstatic int	file_cmp_node(const struct archive_rb_node *,
227231200Smm		    const struct archive_rb_node *);
228231200Smmstatic int	file_cmp_key(const struct archive_rb_node *, const void *);
229231200Smmstatic int	file_new(struct archive_write *a, struct archive_entry *,
230231200Smm		    struct file **);
231231200Smmstatic void	file_free(struct file *);
232231200Smmstatic void	file_register(struct _7zip *, struct file *);
233231200Smmstatic void	file_register_empty(struct _7zip *, struct file *);
234231200Smmstatic void	file_init_register(struct _7zip *);
235231200Smmstatic void	file_init_register_empty(struct _7zip *);
236231200Smmstatic void	file_free_register(struct _7zip *);
237231200Smmstatic ssize_t	compress_out(struct archive_write *, const void *, size_t ,
238231200Smm		    enum la_zaction);
239231200Smmstatic int	compression_init_encoder_copy(struct archive *,
240231200Smm		    struct la_zstream *);
241231200Smmstatic int	compression_code_copy(struct archive *,
242231200Smm		    struct la_zstream *, enum la_zaction);
243231200Smmstatic int	compression_end_copy(struct archive *, struct la_zstream *);
244231200Smmstatic int	compression_init_encoder_deflate(struct archive *,
245231200Smm		    struct la_zstream *, int, int);
246231200Smm#ifdef HAVE_ZLIB_H
247231200Smmstatic int	compression_code_deflate(struct archive *,
248231200Smm		    struct la_zstream *, enum la_zaction);
249231200Smmstatic int	compression_end_deflate(struct archive *, struct la_zstream *);
250231200Smm#endif
251231200Smmstatic int	compression_init_encoder_bzip2(struct archive *,
252231200Smm		    struct la_zstream *, int);
253231200Smm#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
254231200Smmstatic int	compression_code_bzip2(struct archive *,
255231200Smm		    struct la_zstream *, enum la_zaction);
256231200Smmstatic int	compression_end_bzip2(struct archive *, struct la_zstream *);
257231200Smm#endif
258231200Smmstatic int	compression_init_encoder_lzma1(struct archive *,
259231200Smm		    struct la_zstream *, int);
260231200Smmstatic int	compression_init_encoder_lzma2(struct archive *,
261231200Smm		    struct la_zstream *, int);
262231200Smm#if defined(HAVE_LZMA_H)
263231200Smmstatic int	compression_code_lzma(struct archive *,
264231200Smm		    struct la_zstream *, enum la_zaction);
265231200Smmstatic int	compression_end_lzma(struct archive *, struct la_zstream *);
266231200Smm#endif
267231200Smmstatic int	compression_init_encoder_ppmd(struct archive *,
268231200Smm		    struct la_zstream *, unsigned, uint32_t);
269231200Smmstatic int	compression_code_ppmd(struct archive *,
270231200Smm		    struct la_zstream *, enum la_zaction);
271231200Smmstatic int	compression_end_ppmd(struct archive *, struct la_zstream *);
272231200Smmstatic int	_7z_compression_init_encoder(struct archive_write *, unsigned,
273231200Smm		    int);
274231200Smmstatic int	compression_code(struct archive *,
275231200Smm		    struct la_zstream *, enum la_zaction);
276231200Smmstatic int	compression_end(struct archive *,
277231200Smm		    struct la_zstream *);
278231200Smmstatic int	enc_uint64(struct archive_write *, uint64_t);
279231200Smmstatic int	make_header(struct archive_write *, uint64_t, uint64_t,
280231200Smm		    uint64_t, int, struct coder *);
281231200Smmstatic int	make_streamsInfo(struct archive_write *, uint64_t, uint64_t,
282231200Smm		    	uint64_t, int, struct coder *, int, uint32_t);
283231200Smm
284231200Smmint
285231200Smmarchive_write_set_format_7zip(struct archive *_a)
286231200Smm{
287231200Smm	static const struct archive_rb_tree_ops rb_ops = {
288231200Smm		file_cmp_node, file_cmp_key
289231200Smm	};
290231200Smm	struct archive_write *a = (struct archive_write *)_a;
291231200Smm	struct _7zip *zip;
292231200Smm
293231200Smm	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
294231200Smm	    ARCHIVE_STATE_NEW, "archive_write_set_format_7zip");
295231200Smm
296231200Smm	/* If another format was already registered, unregister it. */
297231200Smm	if (a->format_free != NULL)
298231200Smm		(a->format_free)(a);
299231200Smm
300231200Smm	zip = calloc(1, sizeof(*zip));
301231200Smm	if (zip == NULL) {
302231200Smm		archive_set_error(&a->archive, ENOMEM,
303231200Smm		    "Can't allocate 7-Zip data");
304231200Smm		return (ARCHIVE_FATAL);
305231200Smm	}
306231200Smm	zip->temp_fd = -1;
307231200Smm	__archive_rb_tree_init(&(zip->rbtree), &rb_ops);
308231200Smm	file_init_register(zip);
309231200Smm	file_init_register_empty(zip);
310231200Smm
311231200Smm	/* Set default compression type and its level. */
312231200Smm#if HAVE_LZMA_H
313231200Smm	zip->opt_compression = _7Z_LZMA1;
314231200Smm#elif defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
315231200Smm	zip->opt_compression = _7Z_BZIP2;
316231200Smm#elif defined(HAVE_ZLIB_H)
317231200Smm	zip->opt_compression = _7Z_DEFLATE;
318231200Smm#else
319231200Smm	zip->opt_compression = _7Z_COPY;
320231200Smm#endif
321231200Smm	zip->opt_compression_level = 6;
322231200Smm
323231200Smm	a->format_data = zip;
324231200Smm
325231200Smm	a->format_name = "7zip";
326231200Smm	a->format_options = _7z_options;
327231200Smm	a->format_write_header = _7z_write_header;
328231200Smm	a->format_write_data = _7z_write_data;
329231200Smm	a->format_finish_entry = _7z_finish_entry;
330231200Smm	a->format_close = _7z_close;
331231200Smm	a->format_free = _7z_free;
332231200Smm	a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
333231200Smm	a->archive.archive_format_name = "7zip";
334231200Smm
335231200Smm	return (ARCHIVE_OK);
336231200Smm}
337231200Smm
338231200Smmstatic int
339231200Smm_7z_options(struct archive_write *a, const char *key, const char *value)
340231200Smm{
341231200Smm	struct _7zip *zip;
342231200Smm
343231200Smm	zip = (struct _7zip *)a->format_data;
344231200Smm
345231200Smm	if (strcmp(key, "compression") == 0) {
346231200Smm		const char *name = NULL;
347231200Smm
348231200Smm		if (value == NULL || strcmp(value, "copy") == 0 ||
349231200Smm		    strcmp(value, "COPY") == 0 ||
350231200Smm		    strcmp(value, "store") == 0 ||
351231200Smm		    strcmp(value, "STORE") == 0)
352231200Smm			zip->opt_compression = _7Z_COPY;
353231200Smm		else if (strcmp(value, "deflate") == 0 ||
354231200Smm		    strcmp(value, "DEFLATE") == 0)
355231200Smm#if HAVE_ZLIB_H
356231200Smm			zip->opt_compression = _7Z_DEFLATE;
357231200Smm#else
358231200Smm			name = "deflate";
359231200Smm#endif
360231200Smm		else if (strcmp(value, "bzip2") == 0 ||
361231200Smm		    strcmp(value, "BZIP2") == 0)
362231200Smm#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
363231200Smm			zip->opt_compression = _7Z_BZIP2;
364231200Smm#else
365231200Smm			name = "bzip2";
366231200Smm#endif
367231200Smm		else if (strcmp(value, "lzma1") == 0 ||
368231200Smm		    strcmp(value, "LZMA1") == 0)
369231200Smm#if HAVE_LZMA_H
370231200Smm			zip->opt_compression = _7Z_LZMA1;
371231200Smm#else
372231200Smm			name = "lzma1";
373231200Smm#endif
374231200Smm		else if (strcmp(value, "lzma2") == 0 ||
375231200Smm		    strcmp(value, "LZMA2") == 0)
376231200Smm#if HAVE_LZMA_H
377231200Smm			zip->opt_compression = _7Z_LZMA2;
378231200Smm#else
379231200Smm			name = "lzma2";
380231200Smm#endif
381231200Smm		else if (strcmp(value, "ppmd") == 0 ||
382231200Smm		    strcmp(value, "PPMD") == 0 ||
383231200Smm		    strcmp(value, "PPMd") == 0)
384231200Smm			zip->opt_compression = _7Z_PPMD;
385231200Smm		else {
386231200Smm			archive_set_error(&(a->archive),
387231200Smm			    ARCHIVE_ERRNO_MISC,
388231200Smm			    "Unkonwn compression name: `%s'",
389231200Smm			    value);
390231200Smm			return (ARCHIVE_FAILED);
391231200Smm		}
392231200Smm		if (name != NULL) {
393231200Smm			archive_set_error(&(a->archive),
394231200Smm			    ARCHIVE_ERRNO_MISC,
395231200Smm			    "`%s' compression not supported "
396231200Smm			    "on this platform",
397231200Smm			    name);
398231200Smm			return (ARCHIVE_FAILED);
399231200Smm		}
400231200Smm		return (ARCHIVE_OK);
401231200Smm	}
402231200Smm	if (strcmp(key, "compression-level") == 0) {
403231200Smm		if (value == NULL ||
404231200Smm		    !(value[0] >= '0' && value[0] <= '9') ||
405231200Smm		    value[1] != '\0') {
406231200Smm			archive_set_error(&(a->archive),
407231200Smm			    ARCHIVE_ERRNO_MISC,
408231200Smm			    "Illeagal value `%s'",
409231200Smm			    value);
410231200Smm			return (ARCHIVE_FAILED);
411231200Smm		}
412231200Smm		zip->opt_compression_level = value[0] - '0';
413231200Smm		return (ARCHIVE_OK);
414231200Smm	}
415231200Smm
416231200Smm	return (ARCHIVE_FAILED);
417231200Smm}
418231200Smm
419231200Smmstatic int
420231200Smm_7z_write_header(struct archive_write *a, struct archive_entry *entry)
421231200Smm{
422231200Smm	struct _7zip *zip;
423231200Smm	struct file *file;
424231200Smm	int r;
425231200Smm
426231200Smm	zip = (struct _7zip *)a->format_data;
427231200Smm	zip->cur_file = NULL;
428231200Smm	zip->entry_bytes_remaining = 0;
429231200Smm
430231200Smm	if (zip->sconv == NULL) {
431231200Smm		zip->sconv = archive_string_conversion_to_charset(
432231200Smm		    &a->archive, "UTF-16LE", 1);
433231200Smm		if (zip->sconv == NULL)
434231200Smm			return (ARCHIVE_FATAL);
435231200Smm	}
436231200Smm
437231200Smm	r = file_new(a, entry, &file);
438231200Smm	if (r < ARCHIVE_WARN) {
439231200Smm		file_free(file);
440231200Smm		return (r);
441231200Smm	}
442231200Smm
443231200Smm	if (file->flg & MTIME_IS_SET)
444231200Smm		zip->total_number_time_defined[MTIME]++;
445231200Smm	if (file->flg & CTIME_IS_SET)
446231200Smm		zip->total_number_time_defined[CTIME]++;
447231200Smm	if (file->flg & ATIME_IS_SET)
448231200Smm		zip->total_number_time_defined[ATIME]++;
449231200Smm
450231200Smm	if (file->size == 0 && file->dir) {
451231200Smm		if (!__archive_rb_tree_insert_node(&(zip->rbtree),
452231200Smm		    (struct archive_rb_node *)file))
453231200Smm			file_free(file);
454231200Smm	}
455231200Smm	zip->total_number_entry++;
456231200Smm	zip->total_bytes_entry_name += file->name_len + 2;
457231200Smm	if (file->size == 0) {
458231200Smm		/* Count up the number of empty files. */
459231200Smm		zip->total_number_empty_entry++;
460231200Smm		if (file->dir)
461231200Smm			zip->total_number_dir_entry++;
462231200Smm		else
463231200Smm			file_register_empty(zip, file);
464231200Smm		return (r);
465231200Smm	}
466231200Smm
467231200Smm	/*
468231200Smm	 * Init compression.
469231200Smm	 */
470231200Smm	if ((zip->total_number_entry - zip->total_number_empty_entry) == 1) {
471231200Smm		r = _7z_compression_init_encoder(a, zip->opt_compression,
472231200Smm			zip->opt_compression_level);
473231200Smm		if (r < 0) {
474231200Smm			file_free(file);
475231200Smm			return (ARCHIVE_FATAL);
476231200Smm		}
477231200Smm	}
478231200Smm
479231200Smm	/* Register a non-empty file. */
480231200Smm	file_register(zip, file);
481231200Smm
482231200Smm	/*
483231200Smm	 * Set the current file to cur_file to read its contents.
484231200Smm	 */
485231200Smm	zip->cur_file = file;
486231200Smm
487231200Smm
488231200Smm	/* Save a offset of current file in temporary file. */
489231200Smm	zip->entry_bytes_remaining = file->size;
490231200Smm	zip->entry_crc32 = 0;
491231200Smm
492231200Smm	/*
493231200Smm	 * Store a symbolic link name as file contents.
494231200Smm	 */
495231200Smm	if (archive_entry_filetype(entry) == AE_IFLNK) {
496231200Smm		ssize_t bytes;
497231200Smm		const void *p = (const void *)archive_entry_symlink(entry);
498231200Smm		bytes = compress_out(a, p, file->size, ARCHIVE_Z_RUN);
499231200Smm		if (bytes < 0)
500231200Smm			return ((int)bytes);
501231200Smm		zip->entry_crc32 = crc32(zip->entry_crc32, p, bytes);
502231200Smm		zip->entry_bytes_remaining -= bytes;
503231200Smm	}
504231200Smm
505231200Smm	return (r);
506231200Smm}
507231200Smm
508231200Smm/*
509231200Smm * Write data to a temporary file.
510231200Smm */
511231200Smmstatic int
512231200Smmwrite_to_temp(struct archive_write *a, const void *buff, size_t s)
513231200Smm{
514231200Smm	struct _7zip *zip;
515231200Smm	unsigned char *p;
516231200Smm	ssize_t ws;
517231200Smm
518231200Smm	zip = (struct _7zip *)a->format_data;
519231200Smm
520231200Smm	/*
521231200Smm	 * Open a temporary file.
522231200Smm	 */
523231200Smm	if (zip->temp_fd == -1) {
524231200Smm		zip->temp_offset = 0;
525231200Smm		zip->temp_fd = __archive_mktemp(NULL);
526231200Smm		if (zip->temp_fd < 0) {
527231200Smm			archive_set_error(&a->archive, errno,
528231200Smm			    "Couldn't create temporary file");
529231200Smm			return (ARCHIVE_FATAL);
530231200Smm		}
531231200Smm	}
532231200Smm
533231200Smm	p = (unsigned char *)buff;
534231200Smm	while (s) {
535231200Smm		ws = write(zip->temp_fd, p, s);
536231200Smm		if (ws < 0) {
537231200Smm			archive_set_error(&(a->archive), errno,
538231200Smm			    "fwrite function failed");
539231200Smm			return (ARCHIVE_FATAL);
540231200Smm		}
541231200Smm		s -= ws;
542231200Smm		p += ws;
543231200Smm		zip->temp_offset += ws;
544231200Smm	}
545231200Smm	return (ARCHIVE_OK);
546231200Smm}
547231200Smm
548231200Smmstatic ssize_t
549231200Smmcompress_out(struct archive_write *a, const void *buff, size_t s,
550231200Smm    enum la_zaction run)
551231200Smm{
552231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
553231200Smm	int r;
554231200Smm
555231200Smm	if (run == ARCHIVE_Z_FINISH && zip->stream.total_in == 0 && s == 0)
556231200Smm		return (0);
557231200Smm
558231200Smm	if ((zip->crc32flg & PRECODE_CRC32) && s)
559231200Smm		zip->precode_crc32 = crc32(zip->precode_crc32, buff, s);
560231200Smm	zip->stream.next_in = (const unsigned char *)buff;
561231200Smm	zip->stream.avail_in = s;
562231200Smm	do {
563231200Smm		/* Compress file data. */
564231200Smm		r = compression_code(&(a->archive), &(zip->stream), run);
565231200Smm		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
566231200Smm			return (ARCHIVE_FATAL);
567231200Smm		if (zip->stream.avail_out == 0) {
568231200Smm			if (write_to_temp(a, zip->wbuff, sizeof(zip->wbuff))
569231200Smm			    != ARCHIVE_OK)
570231200Smm				return (ARCHIVE_FATAL);
571231200Smm			zip->stream.next_out = zip->wbuff;
572231200Smm			zip->stream.avail_out = sizeof(zip->wbuff);
573231200Smm			if (zip->crc32flg & ENCODED_CRC32)
574231200Smm				zip->encoded_crc32 = crc32(zip->encoded_crc32,
575231200Smm				    zip->wbuff, sizeof(zip->wbuff));
576231200Smm		}
577231200Smm	} while (zip->stream.avail_in);
578231200Smm	if (run == ARCHIVE_Z_FINISH) {
579231200Smm		uint64_t bytes = sizeof(zip->wbuff) - zip->stream.avail_out;
580231200Smm		if (write_to_temp(a, zip->wbuff, bytes) != ARCHIVE_OK)
581231200Smm			return (ARCHIVE_FATAL);
582231200Smm		if ((zip->crc32flg & ENCODED_CRC32) && bytes)
583231200Smm			zip->encoded_crc32 = crc32(zip->encoded_crc32,
584231200Smm			    zip->wbuff, bytes);
585231200Smm	}
586231200Smm
587231200Smm	return (s);
588231200Smm}
589231200Smm
590231200Smmstatic ssize_t
591231200Smm_7z_write_data(struct archive_write *a, const void *buff, size_t s)
592231200Smm{
593231200Smm	struct _7zip *zip;
594231200Smm	ssize_t bytes;
595231200Smm
596231200Smm	zip = (struct _7zip *)a->format_data;
597231200Smm
598231200Smm	if (s > zip->entry_bytes_remaining)
599231200Smm		s = zip->entry_bytes_remaining;
600231200Smm	if (s == 0 || zip->cur_file == NULL)
601231200Smm		return (0);
602231200Smm	bytes = compress_out(a, buff, s, ARCHIVE_Z_RUN);
603231200Smm	if (bytes < 0)
604231200Smm		return (bytes);
605231200Smm	zip->entry_crc32 = crc32(zip->entry_crc32, buff, bytes);
606231200Smm	zip->entry_bytes_remaining -= bytes;
607231200Smm	return (bytes);
608231200Smm}
609231200Smm
610231200Smmstatic int
611231200Smm_7z_finish_entry(struct archive_write *a)
612231200Smm{
613231200Smm	struct _7zip *zip;
614231200Smm	size_t s;
615231200Smm	ssize_t r;
616231200Smm
617231200Smm	zip = (struct _7zip *)a->format_data;
618231200Smm	if (zip->cur_file == NULL)
619231200Smm		return (ARCHIVE_OK);
620231200Smm
621231200Smm	while (zip->entry_bytes_remaining > 0) {
622231200Smm		s = zip->entry_bytes_remaining;
623231200Smm		if (s > a->null_length)
624231200Smm			s = a->null_length;
625231200Smm		r = _7z_write_data(a, a->nulls, s);
626231200Smm		if (r < 0)
627231200Smm			return (r);
628231200Smm	}
629231200Smm	zip->total_bytes_compressed += zip->stream.total_in;
630231200Smm	zip->total_bytes_uncompressed += zip->stream.total_out;
631231200Smm	zip->cur_file->crc32 = zip->entry_crc32;
632231200Smm	zip->cur_file = NULL;
633231200Smm
634231200Smm	return (ARCHIVE_OK);
635231200Smm}
636231200Smm
637231200Smmstatic int
638231200Smmflush_wbuff(struct archive_write *a)
639231200Smm{
640231200Smm	struct _7zip *zip;
641231200Smm	int r;
642231200Smm	size_t s;
643231200Smm
644231200Smm	zip = (struct _7zip *)a->format_data;
645231200Smm	s = sizeof(zip->wbuff) - zip->wbuff_remaining;
646231200Smm	r = __archive_write_output(a, zip->wbuff, s);
647231200Smm	if (r != ARCHIVE_OK)
648231200Smm		return (r);
649231200Smm	zip->wbuff_remaining = sizeof(zip->wbuff);
650231200Smm	return (r);
651231200Smm}
652231200Smm
653231200Smmstatic int
654231200Smmcopy_out(struct archive_write *a, uint64_t offset, uint64_t length)
655231200Smm{
656231200Smm	struct _7zip *zip;
657231200Smm	int r;
658231200Smm
659231200Smm	zip = (struct _7zip *)a->format_data;
660231200Smm	if (zip->temp_offset > 0 &&
661231200Smm	    lseek(zip->temp_fd, offset, SEEK_SET) < 0) {
662231200Smm		archive_set_error(&(a->archive), errno, "lseek failed");
663231200Smm		return (ARCHIVE_FATAL);
664231200Smm	}
665231200Smm	while (length) {
666231200Smm		size_t rsize;
667231200Smm		ssize_t rs;
668231200Smm		unsigned char *wb;
669231200Smm
670231200Smm		if (length > zip->wbuff_remaining)
671231200Smm			rsize = zip->wbuff_remaining;
672231200Smm		else
673231200Smm			rsize = (size_t)length;
674231200Smm		wb = zip->wbuff + (sizeof(zip->wbuff) - zip->wbuff_remaining);
675231200Smm		rs = read(zip->temp_fd, wb, rsize);
676231200Smm		if (rs < 0) {
677231200Smm			archive_set_error(&(a->archive), errno,
678231200Smm			    "Can't read temporary file(%jd)",
679231200Smm			    (intmax_t)rs);
680231200Smm			return (ARCHIVE_FATAL);
681231200Smm		}
682231200Smm		if (rs == 0) {
683231200Smm			archive_set_error(&(a->archive), 0,
684231200Smm			    "Truncated 7-Zip archive");
685231200Smm			return (ARCHIVE_FATAL);
686231200Smm		}
687231200Smm		zip->wbuff_remaining -= rs;
688231200Smm		length -= rs;
689231200Smm		if (zip->wbuff_remaining == 0) {
690231200Smm			r = flush_wbuff(a);
691231200Smm			if (r != ARCHIVE_OK)
692231200Smm				return (r);
693231200Smm		}
694231200Smm	}
695231200Smm	return (ARCHIVE_OK);
696231200Smm}
697231200Smm
698231200Smmstatic int
699231200Smm_7z_close(struct archive_write *a)
700231200Smm{
701231200Smm	struct _7zip *zip;
702231200Smm	unsigned char *wb;
703231200Smm	uint64_t header_offset, header_size, header_unpacksize;
704231200Smm	uint64_t length;
705231200Smm	uint32_t header_crc32;
706231200Smm	int r;
707231200Smm
708231200Smm	zip = (struct _7zip *)a->format_data;
709231200Smm
710231200Smm	if (zip->total_number_entry > 0) {
711231200Smm		struct archive_rb_node *n;
712231200Smm		uint64_t data_offset, data_size, data_unpacksize;
713231200Smm		unsigned header_compression;
714231200Smm
715231200Smm		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
716231200Smm		if (r < 0)
717231200Smm			return (r);
718231200Smm		data_offset = 0;
719231200Smm		data_size = zip->stream.total_out;
720231200Smm		data_unpacksize = zip->stream.total_in;
721231200Smm		zip->coder.codec = zip->opt_compression;
722231200Smm		zip->coder.prop_size = zip->stream.prop_size;
723231200Smm		zip->coder.props = zip->stream.props;
724231200Smm		zip->stream.prop_size = 0;
725231200Smm		zip->stream.props = NULL;
726231200Smm		zip->total_number_nonempty_entry =
727231200Smm		    zip->total_number_entry - zip->total_number_empty_entry;
728231200Smm
729231200Smm		/* Connect an empty file list. */
730231200Smm		if (zip->empty_list.first != NULL) {
731231200Smm			*zip->file_list.last = zip->empty_list.first;
732231200Smm			zip->file_list.last = zip->empty_list.last;
733231200Smm		}
734231200Smm		/* Connect a directory file list. */
735231200Smm		ARCHIVE_RB_TREE_FOREACH(n, &(zip->rbtree)) {
736231200Smm			file_register(zip, (struct file *)n);
737231200Smm		}
738231200Smm
739231200Smm		/*
740231200Smm		 * NOTE: 7z command supports just LZMA1, LZMA2 and COPY for
741231200Smm		 * the compression type for encoding the header.
742231200Smm		 */
743231200Smm#if HAVE_LZMA_H
744231200Smm		header_compression = _7Z_LZMA1;
745231200Smm		/* If the stored file is only one, do not encode the header.
746231200Smm		 * This is the same way 7z command does. */
747231200Smm		if (zip->total_number_entry == 1)
748231200Smm			header_compression = _7Z_COPY;
749231200Smm#else
750231200Smm		header_compression = _7Z_COPY;
751231200Smm#endif
752231200Smm		r = _7z_compression_init_encoder(a, header_compression, 6);
753231200Smm		if (r < 0)
754231200Smm			return (r);
755231200Smm		zip->crc32flg = PRECODE_CRC32;
756231200Smm		zip->precode_crc32 = 0;
757231200Smm		r = make_header(a, data_offset, data_size, data_unpacksize,
758231200Smm			1, &(zip->coder));
759231200Smm		if (r < 0)
760231200Smm			return (r);
761231200Smm		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
762231200Smm		if (r < 0)
763231200Smm			return (r);
764231200Smm		header_offset = data_offset + data_size;
765231200Smm		header_size = zip->stream.total_out;
766231200Smm		header_crc32 = zip->precode_crc32;
767231200Smm		header_unpacksize = zip->stream.total_in;
768231200Smm
769231200Smm		if (header_compression != _7Z_COPY) {
770231200Smm			/*
771231200Smm			 * Encode the header in order to reduce the size
772231200Smm			 * of the archive.
773231200Smm			 */
774231200Smm			free(zip->coder.props);
775231200Smm			zip->coder.codec = header_compression;
776231200Smm			zip->coder.prop_size = zip->stream.prop_size;
777231200Smm			zip->coder.props = zip->stream.props;
778231200Smm			zip->stream.prop_size = 0;
779231200Smm			zip->stream.props = NULL;
780231200Smm
781231200Smm			r = _7z_compression_init_encoder(a, _7Z_COPY, 0);
782231200Smm			if (r < 0)
783231200Smm				return (r);
784231200Smm			zip->crc32flg = ENCODED_CRC32;
785231200Smm			zip->encoded_crc32 = 0;
786231200Smm
787231200Smm			/*
788231200Smm			 * Make EncodedHeader.
789231200Smm			 */
790231200Smm			r = enc_uint64(a, kEncodedHeader);
791231200Smm			if (r < 0)
792231200Smm				return (r);
793231200Smm			r = make_streamsInfo(a, header_offset, header_size,
794231200Smm			      header_unpacksize, 1, &(zip->coder), 0,
795231200Smm			      header_crc32);
796231200Smm			if (r < 0)
797231200Smm				return (r);
798231200Smm			r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
799231200Smm			if (r < 0)
800231200Smm				return (r);
801231200Smm			header_offset = header_offset + header_size;
802231200Smm			header_size = zip->stream.total_out;
803231200Smm			header_crc32 = zip->encoded_crc32;
804231200Smm		}
805231200Smm		zip->crc32flg = 0;
806231200Smm	} else {
807231200Smm		header_offset = header_size = 0;
808231200Smm		header_crc32 = 0;
809231200Smm	}
810231200Smm
811231200Smm	length = zip->temp_offset;
812231200Smm
813231200Smm	/*
814231200Smm	 * Make the zip header on wbuff(write buffer).
815231200Smm	 */
816231200Smm	wb = zip->wbuff;
817231200Smm	zip->wbuff_remaining = sizeof(zip->wbuff);
818231200Smm	memcpy(&wb[0], "7z\xBC\xAF\x27\x1C", 6);
819231200Smm	wb[6] = 0;/* Major version. */
820231200Smm	wb[7] = 3;/* Minor version. */
821231200Smm	archive_le64enc(&wb[12], header_offset);/* Next Header Offset */
822231200Smm	archive_le64enc(&wb[20], header_size);/* Next Header Size */
823231200Smm	archive_le32enc(&wb[28], header_crc32);/* Next Header CRC */
824231200Smm	archive_le32enc(&wb[8], crc32(0, &wb[12], 20));/* Start Header CRC */
825231200Smm	zip->wbuff_remaining -= 32;
826231200Smm
827231200Smm	/*
828231200Smm	 * Read all file contents and an encoded header from the temporary
829231200Smm	 * file and write out it.
830231200Smm	 */
831231200Smm	r = copy_out(a, 0, length);
832231200Smm	if (r != ARCHIVE_OK)
833231200Smm		return (r);
834231200Smm	r = flush_wbuff(a);
835231200Smm	return (r);
836231200Smm}
837231200Smm
838231200Smm/*
839231200Smm * Encode 64 bits value into 7-Zip's encoded UINT64 value.
840231200Smm */
841231200Smmstatic int
842231200Smmenc_uint64(struct archive_write *a, uint64_t val)
843231200Smm{
844231200Smm	unsigned mask = 0x80;
845231200Smm	uint8_t numdata[9];
846231200Smm	int i;
847231200Smm
848231200Smm	numdata[0] = 0;
849231200Smm	for (i = 1; i < sizeof(numdata); i++) {
850231200Smm		if (val < mask) {
851231200Smm			numdata[0] |= (uint8_t)val;
852231200Smm			break;
853231200Smm		}
854231200Smm		numdata[i] = (uint8_t)val;
855231200Smm		val >>= 8;
856231200Smm		numdata[0] |= mask;
857231200Smm		mask >>= 1;
858231200Smm	}
859231200Smm	return (compress_out(a, numdata, i, ARCHIVE_Z_RUN));
860231200Smm}
861231200Smm
862231200Smmstatic int
863231200Smmmake_substreamsInfo(struct archive_write *a, struct coder *coders)
864231200Smm{
865231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
866231200Smm	struct file *file;
867231200Smm	int r;
868231200Smm
869231200Smm	/*
870231200Smm	 * Make SubStreamsInfo.
871231200Smm	 */
872231200Smm	r = enc_uint64(a, kSubStreamsInfo);
873231200Smm	if (r < 0)
874231200Smm		return (r);
875231200Smm
876231200Smm	if (zip->total_number_nonempty_entry > 1 && coders->codec != _7Z_COPY) {
877231200Smm		/*
878231200Smm		 * Make NumUnPackStream.
879231200Smm		 */
880231200Smm		r = enc_uint64(a, kNumUnPackStream);
881231200Smm		if (r < 0)
882231200Smm			return (r);
883231200Smm
884231200Smm		/* Write numUnpackStreams */
885231200Smm		r = enc_uint64(a, zip->total_number_nonempty_entry);
886231200Smm		if (r < 0)
887231200Smm			return (r);
888231200Smm
889231200Smm		/*
890231200Smm		 * Make kSize.
891231200Smm		 */
892231200Smm		r = enc_uint64(a, kSize);
893231200Smm		if (r < 0)
894231200Smm			return (r);
895231200Smm		file = zip->file_list.first;
896231200Smm		for (;file != NULL; file = file->next) {
897231200Smm			if (file->next == NULL ||
898231200Smm			    file->next->size == 0)
899231200Smm				break;
900231200Smm			r = enc_uint64(a, file->size);
901231200Smm			if (r < 0)
902231200Smm				return (r);
903231200Smm		}
904231200Smm	}
905231200Smm
906231200Smm	/*
907231200Smm	 * Make CRC.
908231200Smm	 */
909231200Smm	r = enc_uint64(a, kCRC);
910231200Smm	if (r < 0)
911231200Smm		return (r);
912231200Smm
913231200Smm
914231200Smm	/* All are defined */
915231200Smm	r = enc_uint64(a, 1);
916231200Smm	if (r < 0)
917231200Smm		return (r);
918231200Smm	file = zip->file_list.first;
919231200Smm	for (;file != NULL; file = file->next) {
920231200Smm		uint8_t crc[4];
921231200Smm		if (file->size == 0)
922231200Smm			break;
923231200Smm		archive_le32enc(crc, file->crc32);
924231200Smm		r = compress_out(a, crc, 4, ARCHIVE_Z_RUN);
925231200Smm		if (r < 0)
926231200Smm			return (r);
927231200Smm	}
928231200Smm
929231200Smm	/* Write End. */
930231200Smm	r = enc_uint64(a, kEnd);
931231200Smm	if (r < 0)
932231200Smm		return (r);
933231200Smm	return (ARCHIVE_OK);
934231200Smm}
935231200Smm
936231200Smmstatic int
937231200Smmmake_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
938231200Smm    uint64_t unpack_size, int num_coder, struct coder *coders, int substrm,
939231200Smm    uint32_t header_crc)
940231200Smm{
941231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
942231200Smm	uint8_t codec_buff[8];
943231200Smm	int numFolders, fi;
944231200Smm	int codec_size;
945231200Smm	int i, r;
946231200Smm
947231200Smm	if (coders->codec == _7Z_COPY)
948231200Smm		numFolders = zip->total_number_nonempty_entry;
949231200Smm	else
950231200Smm		numFolders = 1;
951231200Smm
952231200Smm	/*
953231200Smm	 * Make PackInfo.
954231200Smm	 */
955231200Smm	r = enc_uint64(a, kPackInfo);
956231200Smm	if (r < 0)
957231200Smm		return (r);
958231200Smm
959231200Smm	/* Write PackPos. */
960231200Smm	r = enc_uint64(a, offset);
961231200Smm	if (r < 0)
962231200Smm		return (r);
963231200Smm
964231200Smm	/* Write NumPackStreams. */
965231200Smm	r = enc_uint64(a, numFolders);
966231200Smm	if (r < 0)
967231200Smm		return (r);
968231200Smm
969231200Smm	/* Make Size. */
970231200Smm	r = enc_uint64(a, kSize);
971231200Smm	if (r < 0)
972231200Smm		return (r);
973231200Smm
974231200Smm	if (numFolders > 1) {
975231200Smm		struct file *file = zip->file_list.first;
976231200Smm		for (;file != NULL; file = file->next) {
977231200Smm			if (file->size == 0)
978231200Smm				break;
979231200Smm			r = enc_uint64(a, file->size);
980231200Smm			if (r < 0)
981231200Smm				return (r);
982231200Smm		}
983231200Smm	} else {
984231200Smm		/* Write size. */
985231200Smm		r = enc_uint64(a, pack_size);
986231200Smm		if (r < 0)
987231200Smm			return (r);
988231200Smm	}
989231200Smm
990231200Smm	r = enc_uint64(a, kEnd);
991231200Smm	if (r < 0)
992231200Smm		return (r);
993231200Smm
994231200Smm	/*
995231200Smm	 * Make UnPackInfo.
996231200Smm	 */
997231200Smm	r = enc_uint64(a, kUnPackInfo);
998231200Smm	if (r < 0)
999231200Smm		return (r);
1000231200Smm
1001231200Smm	/*
1002231200Smm	 * Make Folder.
1003231200Smm	 */
1004231200Smm	r = enc_uint64(a, kFolder);
1005231200Smm	if (r < 0)
1006231200Smm		return (r);
1007231200Smm
1008231200Smm	/* Write NumFolders. */
1009231200Smm	r = enc_uint64(a, numFolders);
1010231200Smm	if (r < 0)
1011231200Smm		return (r);
1012231200Smm
1013231200Smm	/* Write External. */
1014231200Smm	r = enc_uint64(a, 0);
1015231200Smm	if (r < 0)
1016231200Smm		return (r);
1017231200Smm
1018231200Smm	for (fi = 0; fi < numFolders; fi++) {
1019231200Smm		/* Write NumCoders. */
1020231200Smm		r = enc_uint64(a, num_coder);
1021231200Smm		if (r < 0)
1022231200Smm			return (r);
1023231200Smm
1024231200Smm		for (i = 0; i < num_coder; i++) {
1025231200Smm			unsigned codec_id = coders[i].codec;
1026231200Smm
1027231200Smm			/* Write Codec flag. */
1028231200Smm			archive_be64enc(codec_buff, codec_id);
1029231200Smm			for (codec_size = 8; codec_size > 0; codec_size--) {
1030231200Smm				if (codec_buff[8 - codec_size])
1031231200Smm					break;
1032231200Smm			}
1033231200Smm			if (codec_size == 0)
1034231200Smm				codec_size = 1;
1035231200Smm			if (coders[i].prop_size)
1036231200Smm				r = enc_uint64(a, codec_size | 0x20);
1037231200Smm			else
1038231200Smm				r = enc_uint64(a, codec_size);
1039231200Smm			if (r < 0)
1040231200Smm				return (r);
1041231200Smm
1042231200Smm			/* Write Codec ID. */
1043231200Smm			codec_size &= 0x0f;
1044231200Smm			r = compress_out(a, &codec_buff[8-codec_size],
1045231200Smm				codec_size, ARCHIVE_Z_RUN);
1046231200Smm			if (r < 0)
1047231200Smm				return (r);
1048231200Smm
1049231200Smm			if (coders[i].prop_size) {
1050231200Smm				/* Write Codec property size. */
1051231200Smm				r = enc_uint64(a, coders[i].prop_size);
1052231200Smm				if (r < 0)
1053231200Smm					return (r);
1054231200Smm
1055231200Smm				/* Write Codec properties. */
1056231200Smm				r = compress_out(a, coders[i].props,
1057231200Smm					coders[i].prop_size, ARCHIVE_Z_RUN);
1058231200Smm				if (r < 0)
1059231200Smm					return (r);
1060231200Smm			}
1061231200Smm		}
1062231200Smm	}
1063231200Smm
1064231200Smm	/*
1065231200Smm	 * Make CodersUnPackSize.
1066231200Smm	 */
1067231200Smm	r = enc_uint64(a, kCodersUnPackSize);
1068231200Smm	if (r < 0)
1069231200Smm		return (r);
1070231200Smm
1071231200Smm	if (numFolders > 1) {
1072231200Smm		struct file *file = zip->file_list.first;
1073231200Smm		for (;file != NULL; file = file->next) {
1074231200Smm			if (file->size == 0)
1075231200Smm				break;
1076231200Smm			r = enc_uint64(a, file->size);
1077231200Smm			if (r < 0)
1078231200Smm				return (r);
1079231200Smm		}
1080231200Smm
1081231200Smm	} else {
1082231200Smm		/* Write UnPackSize. */
1083231200Smm		r = enc_uint64(a, unpack_size);
1084231200Smm		if (r < 0)
1085231200Smm			return (r);
1086231200Smm	}
1087231200Smm
1088231200Smm	if (!substrm) {
1089231200Smm		uint8_t crc[4];
1090231200Smm		/*
1091231200Smm		 * Make CRC.
1092231200Smm		 */
1093231200Smm		r = enc_uint64(a, kCRC);
1094231200Smm		if (r < 0)
1095231200Smm			return (r);
1096231200Smm
1097231200Smm		/* All are defined */
1098231200Smm		r = enc_uint64(a, 1);
1099231200Smm		if (r < 0)
1100231200Smm			return (r);
1101231200Smm		archive_le32enc(crc, header_crc);
1102231200Smm		r = compress_out(a, crc, 4, ARCHIVE_Z_RUN);
1103231200Smm		if (r < 0)
1104231200Smm			return (r);
1105231200Smm	}
1106231200Smm
1107231200Smm	/* Write End. */
1108231200Smm	r = enc_uint64(a, kEnd);
1109231200Smm	if (r < 0)
1110231200Smm		return (r);
1111231200Smm
1112231200Smm	if (substrm) {
1113231200Smm		/*
1114231200Smm		 * Make SubStreamsInfo.
1115231200Smm		 */
1116231200Smm		r = make_substreamsInfo(a, coders);
1117231200Smm		if (r < 0)
1118231200Smm			return (r);
1119231200Smm	}
1120231200Smm
1121231200Smm
1122231200Smm	/* Write End. */
1123231200Smm	r = enc_uint64(a, kEnd);
1124231200Smm	if (r < 0)
1125231200Smm		return (r);
1126231200Smm
1127231200Smm	return (ARCHIVE_OK);
1128231200Smm}
1129231200Smm
1130231200Smm
1131231200Smm#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
1132231200Smmstatic uint64_t
1133231200SmmutcToFiletime(time_t time, long ns)
1134231200Smm{
1135231200Smm	uint64_t fileTime;
1136231200Smm
1137231200Smm	fileTime = time;
1138231200Smm	fileTime *= 10000000;
1139231200Smm	fileTime += ns / 100;
1140231200Smm	fileTime += EPOC_TIME;
1141231200Smm	return (fileTime);
1142231200Smm}
1143231200Smm
1144231200Smmstatic int
1145231200Smmmake_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)
1146231200Smm{
1147231200Smm	uint8_t filetime[8];
1148231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
1149231200Smm	struct file *file;
1150231200Smm	int r;
1151231200Smm	uint8_t mask, byte;
1152231200Smm
1153231200Smm	/*
1154231200Smm	 * Make Time Bools.
1155231200Smm	 */
1156231200Smm	if (zip->total_number_time_defined[ti] == zip->total_number_entry) {
1157231200Smm		/* Write Time Type. */
1158231200Smm		r = enc_uint64(a, type);
1159231200Smm		if (r < 0)
1160231200Smm			return (r);
1161231200Smm		/* Write EmptyStream Size. */
1162231200Smm		r = enc_uint64(a, 2 + zip->total_number_entry * 8);
1163231200Smm		if (r < 0)
1164231200Smm			return (r);
1165231200Smm		/* All are defined. */
1166231200Smm		r = enc_uint64(a, 1);
1167231200Smm		if (r < 0)
1168231200Smm			return (r);
1169231200Smm	} else {
1170231200Smm		if (zip->total_number_time_defined[ti] == 0)
1171231200Smm			return (ARCHIVE_OK);
1172231200Smm
1173231200Smm		/* Write Time Type. */
1174231200Smm		r = enc_uint64(a, type);
1175231200Smm		if (r < 0)
1176231200Smm			return (r);
1177231200Smm		/* Write EmptyStream Size. */
1178231200Smm		r = enc_uint64(a, 2 + ((zip->total_number_entry + 7) >> 3)
1179231200Smm			+ zip->total_number_time_defined[ti] * 8);
1180231200Smm		if (r < 0)
1181231200Smm			return (r);
1182231200Smm
1183231200Smm		/* All are not defined. */
1184231200Smm		r = enc_uint64(a, 0);
1185231200Smm		if (r < 0)
1186231200Smm			return (r);
1187231200Smm
1188231200Smm		byte = 0;
1189231200Smm		mask = 0x80;
1190231200Smm		file = zip->file_list.first;
1191231200Smm		for (;file != NULL; file = file->next) {
1192231200Smm			if (file->flg & flg)
1193231200Smm				byte |= mask;
1194231200Smm			mask >>= 1;
1195231200Smm			if (mask == 0) {
1196231200Smm				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
1197231200Smm				if (r < 0)
1198231200Smm					return (r);
1199231200Smm				mask = 0x80;
1200231200Smm				byte = 0;
1201231200Smm			}
1202231200Smm		}
1203231200Smm		if (mask != 0x80) {
1204231200Smm			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
1205231200Smm			if (r < 0)
1206231200Smm				return (r);
1207231200Smm		}
1208231200Smm	}
1209231200Smm
1210231200Smm	/* External. */
1211231200Smm	r = enc_uint64(a, 0);
1212231200Smm	if (r < 0)
1213231200Smm		return (r);
1214231200Smm
1215231200Smm
1216231200Smm	/*
1217231200Smm	 * Make Times.
1218231200Smm	 */
1219231200Smm	file = zip->file_list.first;
1220231200Smm	for (;file != NULL; file = file->next) {
1221231200Smm		if ((file->flg & flg) == 0)
1222231200Smm			continue;
1223231200Smm		archive_le64enc(filetime, utcToFiletime(file->times[ti].time,
1224231200Smm			file->times[ti].time_ns));
1225231200Smm		r = compress_out(a, filetime, 8, ARCHIVE_Z_RUN);
1226231200Smm		if (r < 0)
1227231200Smm			return (r);
1228231200Smm	}
1229231200Smm
1230231200Smm	return (ARCHIVE_OK);
1231231200Smm}
1232231200Smm
1233231200Smmstatic int
1234231200Smmmake_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
1235231200Smm    uint64_t unpack_size, int codernum, struct coder *coders)
1236231200Smm{
1237231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
1238231200Smm	struct file *file;
1239231200Smm	int r;
1240231200Smm	uint8_t mask, byte;
1241231200Smm
1242231200Smm	/*
1243231200Smm	 * Make FilesInfo.
1244231200Smm	 */
1245231200Smm	r = enc_uint64(a, kHeader);
1246231200Smm	if (r < 0)
1247231200Smm		return (r);
1248231200Smm
1249231200Smm	/*
1250231200Smm	 * If there are empty files only, do not write MainStreamInfo.
1251231200Smm	 */
1252231200Smm	if (zip->total_number_nonempty_entry) {
1253231200Smm		/*
1254231200Smm		 * Make MainStreamInfo.
1255231200Smm		 */
1256231200Smm		r = enc_uint64(a, kMainStreamsInfo);
1257231200Smm		if (r < 0)
1258231200Smm			return (r);
1259231200Smm		r = make_streamsInfo(a, offset, pack_size, unpack_size,
1260231200Smm		      codernum, coders, 1, 0);
1261231200Smm		if (r < 0)
1262231200Smm			return (r);
1263231200Smm	}
1264231200Smm
1265231200Smm	/*
1266231200Smm	 * Make FilesInfo.
1267231200Smm	 */
1268231200Smm	r = enc_uint64(a, kFilesInfo);
1269231200Smm	if (r < 0)
1270231200Smm		return (r);
1271231200Smm
1272231200Smm	/* Write numFiles. */
1273231200Smm	r = enc_uint64(a, zip->total_number_entry);
1274231200Smm	if (r < 0)
1275231200Smm		return (r);
1276231200Smm
1277231200Smm	if (zip->total_number_empty_entry > 0) {
1278231200Smm		/* Make EmptyStream. */
1279231200Smm		r = enc_uint64(a, kEmptyStream);
1280231200Smm		if (r < 0)
1281231200Smm			return (r);
1282231200Smm
1283231200Smm		/* Write EmptyStream Size. */
1284231200Smm		r = enc_uint64(a, (zip->total_number_entry+7)>>3);
1285231200Smm		if (r < 0)
1286231200Smm			return (r);
1287231200Smm
1288231200Smm		byte = 0;
1289231200Smm		mask = 0x80;
1290231200Smm		file = zip->file_list.first;
1291231200Smm		for (;file != NULL; file = file->next) {
1292231200Smm			if (file->size == 0)
1293231200Smm				byte |= mask;
1294231200Smm			mask >>= 1;
1295231200Smm			if (mask == 0) {
1296231200Smm				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
1297231200Smm				if (r < 0)
1298231200Smm					return (r);
1299231200Smm				mask = 0x80;
1300231200Smm				byte = 0;
1301231200Smm			}
1302231200Smm		}
1303231200Smm		if (mask != 0x80) {
1304231200Smm			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
1305231200Smm			if (r < 0)
1306231200Smm				return (r);
1307231200Smm		}
1308231200Smm	}
1309231200Smm
1310231200Smm	if (zip->total_number_empty_entry > zip->total_number_dir_entry) {
1311231200Smm		/* Make EmptyFile. */
1312231200Smm		r = enc_uint64(a, kEmptyFile);
1313231200Smm		if (r < 0)
1314231200Smm			return (r);
1315231200Smm
1316231200Smm		/* Write EmptyFile Size. */
1317231200Smm		r = enc_uint64(a, (zip->total_number_empty_entry + 7) >> 3);
1318231200Smm		if (r < 0)
1319231200Smm			return (r);
1320231200Smm
1321231200Smm		byte = 0;
1322231200Smm		mask = 0x80;
1323231200Smm		file = zip->file_list.first;
1324231200Smm		for (;file != NULL; file = file->next) {
1325231200Smm			if (file->size)
1326231200Smm				continue;
1327231200Smm			if (!file->dir)
1328231200Smm				byte |= mask;
1329231200Smm			mask >>= 1;
1330231200Smm			if (mask == 0) {
1331231200Smm				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
1332231200Smm				if (r < 0)
1333231200Smm					return (r);
1334231200Smm				mask = 0x80;
1335231200Smm				byte = 0;
1336231200Smm			}
1337231200Smm		}
1338231200Smm		if (mask != 0x80) {
1339231200Smm			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
1340231200Smm			if (r < 0)
1341231200Smm				return (r);
1342231200Smm		}
1343231200Smm	}
1344231200Smm
1345231200Smm	/* Make Name. */
1346231200Smm	r = enc_uint64(a, kName);
1347231200Smm	if (r < 0)
1348231200Smm		return (r);
1349231200Smm
1350231200Smm	/* Write Nume size. */
1351231200Smm	r = enc_uint64(a, zip->total_bytes_entry_name+1);
1352231200Smm	if (r < 0)
1353231200Smm		return (r);
1354231200Smm
1355231200Smm	/* Write dmy byte. */
1356231200Smm	r = enc_uint64(a, 0);
1357231200Smm	if (r < 0)
1358231200Smm		return (r);
1359231200Smm
1360231200Smm	file = zip->file_list.first;
1361231200Smm	for (;file != NULL; file = file->next) {
1362231200Smm		r = compress_out(a, file->utf16name, file->name_len+2,
1363231200Smm			ARCHIVE_Z_RUN);
1364231200Smm		if (r < 0)
1365231200Smm			return (r);
1366231200Smm	}
1367231200Smm
1368231200Smm	/* Make MTime. */
1369231200Smm	r = make_time(a, kMTime, MTIME_IS_SET, MTIME);
1370231200Smm	if (r < 0)
1371231200Smm		return (r);
1372231200Smm
1373231200Smm	/* Make CTime. */
1374231200Smm	r = make_time(a, kCTime, CTIME_IS_SET, CTIME);
1375231200Smm	if (r < 0)
1376231200Smm		return (r);
1377231200Smm
1378231200Smm	/* Make ATime. */
1379231200Smm	r = make_time(a, kATime, ATIME_IS_SET, ATIME);
1380231200Smm	if (r < 0)
1381231200Smm		return (r);
1382231200Smm
1383231200Smm	/* Make Attributes. */
1384231200Smm	r = enc_uint64(a, kAttributes);
1385231200Smm	if (r < 0)
1386231200Smm		return (r);
1387231200Smm
1388231200Smm	/* Write Attributes size. */
1389231200Smm	r = enc_uint64(a, 2 + zip->total_number_entry * 4);
1390231200Smm	if (r < 0)
1391231200Smm		return (r);
1392231200Smm
1393231200Smm	/* Write "All Are Defined". */
1394231200Smm	r = enc_uint64(a, 1);
1395231200Smm	if (r < 0)
1396231200Smm		return (r);
1397231200Smm
1398231200Smm	/* Write dmy byte. */
1399231200Smm	r = enc_uint64(a, 0);
1400231200Smm	if (r < 0)
1401231200Smm		return (r);
1402231200Smm
1403231200Smm	file = zip->file_list.first;
1404231200Smm	for (;file != NULL; file = file->next) {
1405231200Smm		/*
1406231200Smm		 * High 16bits is unix mode.
1407231200Smm		 * Low 16bits is Windows attributes.
1408231200Smm		 */
1409231200Smm		uint32_t encattr, attr;
1410231200Smm		if (file->dir)
1411231200Smm			attr = 0x8010;
1412231200Smm		else
1413231200Smm			attr = 0x8020;
1414231200Smm		if ((file->mode & 0222) == 0)
1415231200Smm			attr |= 1;/* Read Only. */
1416231200Smm		attr |= ((uint32_t)file->mode) << 16;
1417231200Smm		archive_le32enc(&encattr, attr);
1418231200Smm		r = compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);
1419231200Smm		if (r < 0)
1420231200Smm			return (r);
1421231200Smm	}
1422231200Smm
1423231200Smm	/* Write End. */
1424231200Smm	r = enc_uint64(a, kEnd);
1425231200Smm	if (r < 0)
1426231200Smm		return (r);
1427231200Smm
1428231200Smm	/* Write End. */
1429231200Smm	r = enc_uint64(a, kEnd);
1430231200Smm	if (r < 0)
1431231200Smm		return (r);
1432231200Smm
1433231200Smm	return (ARCHIVE_OK);
1434231200Smm}
1435231200Smm
1436231200Smm
1437231200Smmstatic int
1438231200Smm_7z_free(struct archive_write *a)
1439231200Smm{
1440231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
1441231200Smm
1442231200Smm	file_free_register(zip);
1443231200Smm	compression_end(&(a->archive), &(zip->stream));
1444231200Smm	free(zip->coder.props);
1445231200Smm	free(zip);
1446231200Smm
1447231200Smm	return (ARCHIVE_OK);
1448231200Smm}
1449231200Smm
1450231200Smmstatic int
1451231200Smmfile_cmp_node(const struct archive_rb_node *n1,
1452231200Smm    const struct archive_rb_node *n2)
1453231200Smm{
1454231200Smm	struct file *f1 = (struct file *)n1;
1455231200Smm	struct file *f2 = (struct file *)n2;
1456231200Smm
1457231200Smm	if (f1->name_len == f2->name_len)
1458231200Smm		return (memcmp(f1->utf16name, f2->utf16name, f1->name_len));
1459231200Smm	return (f1->name_len > f2->name_len)?1:-1;
1460231200Smm}
1461231200Smm
1462231200Smmstatic int
1463231200Smmfile_cmp_key(const struct archive_rb_node *n, const void *key)
1464231200Smm{
1465231200Smm	struct file *f = (struct file *)n;
1466231200Smm
1467231200Smm	return (f->name_len - *(const char *)key);
1468231200Smm}
1469231200Smm
1470231200Smmstatic int
1471231200Smmfile_new(struct archive_write *a, struct archive_entry *entry,
1472231200Smm    struct file **newfile)
1473231200Smm{
1474231200Smm	struct _7zip *zip;
1475231200Smm	struct file *file;
1476231200Smm	const char *u16;
1477231200Smm	size_t u16len;
1478231200Smm	int ret = ARCHIVE_OK;
1479231200Smm
1480231200Smm	zip = (struct _7zip *)a->format_data;
1481231200Smm	*newfile = NULL;
1482231200Smm
1483231200Smm	file = calloc(1, sizeof(*file));
1484231200Smm	if (file == NULL) {
1485231200Smm		archive_set_error(&a->archive, ENOMEM,
1486231200Smm		    "Can't allocate memory");
1487231200Smm		return (ARCHIVE_FATAL);
1488231200Smm	}
1489231200Smm
1490231200Smm	if (0 > archive_entry_pathname_l(entry, &u16, &u16len, zip->sconv)) {
1491231200Smm		if (errno == ENOMEM) {
1492231200Smm			archive_set_error(&a->archive, ENOMEM,
1493231200Smm			    "Can't allocate memory for UTF-16LE");
1494231200Smm			return (ARCHIVE_FATAL);
1495231200Smm		}
1496231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1497231200Smm		    "A filename cannot be converted to UTF-16LE;"
1498231200Smm		    "You should disable making Joliet extension");
1499231200Smm		ret = ARCHIVE_WARN;
1500231200Smm	}
1501231200Smm	file->utf16name = malloc(u16len + 2);
1502231200Smm	if (file->utf16name == NULL) {
1503231200Smm		archive_set_error(&a->archive, ENOMEM,
1504231200Smm		    "Can't allocate memory for Name");
1505231200Smm		return (ARCHIVE_FATAL);
1506231200Smm	}
1507231200Smm	memcpy(file->utf16name, u16, u16len);
1508231200Smm	file->utf16name[u16len+0] = 0;
1509231200Smm	file->utf16name[u16len+1] = 0;
1510231200Smm	file->name_len = u16len;
1511231200Smm	file->mode = archive_entry_mode(entry);
1512231200Smm	if (archive_entry_filetype(entry) == AE_IFREG)
1513231200Smm		file->size = archive_entry_size(entry);
1514231200Smm	else
1515231200Smm		archive_entry_set_size(entry, 0);
1516231200Smm	if (archive_entry_filetype(entry) == AE_IFDIR)
1517231200Smm		file->dir = 1;
1518231200Smm	else if (archive_entry_filetype(entry) == AE_IFLNK)
1519231200Smm		file->size = strlen(archive_entry_symlink(entry));
1520231200Smm	if (archive_entry_mtime_is_set(entry)) {
1521231200Smm		file->flg |= MTIME_IS_SET;
1522231200Smm		file->times[MTIME].time = archive_entry_mtime(entry);
1523231200Smm		file->times[MTIME].time_ns = archive_entry_mtime_nsec(entry);
1524231200Smm	}
1525231200Smm	if (archive_entry_atime_is_set(entry)) {
1526231200Smm		file->flg |= ATIME_IS_SET;
1527231200Smm		file->times[ATIME].time = archive_entry_atime(entry);
1528231200Smm		file->times[ATIME].time_ns = archive_entry_atime_nsec(entry);
1529231200Smm	}
1530231200Smm	if (archive_entry_ctime_is_set(entry)) {
1531231200Smm		file->flg |= CTIME_IS_SET;
1532231200Smm		file->times[CTIME].time = archive_entry_ctime(entry);
1533231200Smm		file->times[CTIME].time_ns = archive_entry_ctime_nsec(entry);
1534231200Smm	}
1535231200Smm
1536231200Smm	*newfile = file;
1537231200Smm	return (ret);
1538231200Smm}
1539231200Smm
1540231200Smmstatic void
1541231200Smmfile_free(struct file *file)
1542231200Smm{
1543231200Smm	free(file->utf16name);
1544231200Smm	free(file);
1545231200Smm}
1546231200Smm
1547231200Smmstatic void
1548231200Smmfile_register(struct _7zip *zip, struct file *file)
1549231200Smm{
1550231200Smm	file->next = NULL;
1551231200Smm	*zip->file_list.last = file;
1552231200Smm	zip->file_list.last = &(file->next);
1553231200Smm}
1554231200Smm
1555231200Smmstatic void
1556231200Smmfile_init_register(struct _7zip *zip)
1557231200Smm{
1558231200Smm	zip->file_list.first = NULL;
1559231200Smm	zip->file_list.last = &(zip->file_list.first);
1560231200Smm}
1561231200Smm
1562231200Smmstatic void
1563231200Smmfile_free_register(struct _7zip *zip)
1564231200Smm{
1565231200Smm	struct file *file, *file_next;
1566231200Smm
1567231200Smm	file = zip->file_list.first;
1568231200Smm	while (file != NULL) {
1569231200Smm		file_next = file->next;
1570231200Smm		file_free(file);
1571231200Smm		file = file_next;
1572231200Smm	}
1573231200Smm}
1574231200Smm
1575231200Smmstatic void
1576231200Smmfile_register_empty(struct _7zip *zip, struct file *file)
1577231200Smm{
1578231200Smm	file->next = NULL;
1579231200Smm	*zip->empty_list.last = file;
1580231200Smm	zip->empty_list.last = &(file->next);
1581231200Smm}
1582231200Smm
1583231200Smmstatic void
1584231200Smmfile_init_register_empty(struct _7zip *zip)
1585231200Smm{
1586231200Smm	zip->empty_list.first = NULL;
1587231200Smm	zip->empty_list.last = &(zip->empty_list.first);
1588231200Smm}
1589231200Smm
1590231200Smm#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
1591231200Smmstatic int
1592231200Smmcompression_unsupported_encoder(struct archive *a,
1593231200Smm    struct la_zstream *lastrm, const char *name)
1594231200Smm{
1595231200Smm
1596231200Smm	archive_set_error(a, ARCHIVE_ERRNO_MISC,
1597231200Smm	    "%s compression not supported on this platform", name);
1598231200Smm	lastrm->valid = 0;
1599231200Smm	lastrm->real_stream = NULL;
1600231200Smm	return (ARCHIVE_FAILED);
1601231200Smm}
1602231200Smm#endif
1603231200Smm
1604231200Smm/*
1605231200Smm * _7_COPY compressor.
1606231200Smm */
1607231200Smmstatic int
1608231200Smmcompression_init_encoder_copy(struct archive *a, struct la_zstream *lastrm)
1609231200Smm{
1610231200Smm
1611231200Smm	if (lastrm->valid)
1612231200Smm		compression_end(a, lastrm);
1613231200Smm	lastrm->valid = 1;
1614231200Smm	lastrm->code = compression_code_copy;
1615231200Smm	lastrm->end = compression_end_copy;
1616231200Smm	return (ARCHIVE_OK);
1617231200Smm}
1618231200Smm
1619231200Smmstatic int
1620231200Smmcompression_code_copy(struct archive *a,
1621231200Smm    struct la_zstream *lastrm, enum la_zaction action)
1622231200Smm{
1623231200Smm	size_t bytes;
1624231200Smm
1625231200Smm	(void)a; /* UNUSED */
1626231200Smm	if (lastrm->avail_out > lastrm->avail_in)
1627231200Smm		bytes = lastrm->avail_in;
1628231200Smm	else
1629231200Smm		bytes = lastrm->avail_out;
1630231200Smm	if (bytes) {
1631231200Smm		memcpy(lastrm->next_out, lastrm->next_in, bytes);
1632231200Smm		lastrm->next_in += bytes;
1633231200Smm		lastrm->avail_in -= bytes;
1634231200Smm		lastrm->total_in += bytes;
1635231200Smm		lastrm->next_out += bytes;
1636231200Smm		lastrm->avail_out -= bytes;
1637231200Smm		lastrm->total_out += bytes;
1638231200Smm	}
1639231200Smm	if (action == ARCHIVE_Z_FINISH && lastrm->avail_in == 0)
1640231200Smm		return (ARCHIVE_EOF);
1641231200Smm	return (ARCHIVE_OK);
1642231200Smm}
1643231200Smm
1644231200Smmstatic int
1645231200Smmcompression_end_copy(struct archive *a, struct la_zstream *lastrm)
1646231200Smm{
1647231200Smm	(void)a; /* UNUSED */
1648231200Smm	lastrm->valid = 0;
1649231200Smm	return (ARCHIVE_OK);
1650231200Smm}
1651231200Smm
1652231200Smm/*
1653231200Smm * _7_DEFLATE compressor.
1654231200Smm */
1655231200Smm#ifdef HAVE_ZLIB_H
1656231200Smmstatic int
1657231200Smmcompression_init_encoder_deflate(struct archive *a,
1658231200Smm    struct la_zstream *lastrm, int level, int withheader)
1659231200Smm{
1660231200Smm	z_stream *strm;
1661231200Smm
1662231200Smm	if (lastrm->valid)
1663231200Smm		compression_end(a, lastrm);
1664231200Smm	strm = calloc(1, sizeof(*strm));
1665231200Smm	if (strm == NULL) {
1666231200Smm		archive_set_error(a, ENOMEM,
1667231200Smm		    "Can't allocate memory for gzip stream");
1668231200Smm		return (ARCHIVE_FATAL);
1669231200Smm	}
1670231200Smm	/* zlib.h is not const-correct, so we need this one bit
1671231200Smm	 * of ugly hackery to convert a const * pointer to
1672231200Smm	 * a non-const pointer. */
1673231200Smm	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
1674231200Smm	strm->avail_in = lastrm->avail_in;
1675231200Smm	strm->total_in = lastrm->total_in;
1676231200Smm	strm->next_out = lastrm->next_out;
1677231200Smm	strm->avail_out = lastrm->avail_out;
1678231200Smm	strm->total_out = lastrm->total_out;
1679231200Smm	if (deflateInit2(strm, level, Z_DEFLATED,
1680231200Smm	    (withheader)?15:-15,
1681231200Smm	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
1682231200Smm		free(strm);
1683231200Smm		lastrm->real_stream = NULL;
1684231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1685231200Smm		    "Internal error initializing compression library");
1686231200Smm		return (ARCHIVE_FATAL);
1687231200Smm	}
1688231200Smm	lastrm->real_stream = strm;
1689231200Smm	lastrm->valid = 1;
1690231200Smm	lastrm->code = compression_code_deflate;
1691231200Smm	lastrm->end = compression_end_deflate;
1692231200Smm	return (ARCHIVE_OK);
1693231200Smm}
1694231200Smm
1695231200Smmstatic int
1696231200Smmcompression_code_deflate(struct archive *a,
1697231200Smm    struct la_zstream *lastrm, enum la_zaction action)
1698231200Smm{
1699231200Smm	z_stream *strm;
1700231200Smm	int r;
1701231200Smm
1702231200Smm	strm = (z_stream *)lastrm->real_stream;
1703231200Smm	/* zlib.h is not const-correct, so we need this one bit
1704231200Smm	 * of ugly hackery to convert a const * pointer to
1705231200Smm	 * a non-const pointer. */
1706231200Smm	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
1707231200Smm	strm->avail_in = lastrm->avail_in;
1708231200Smm	strm->total_in = lastrm->total_in;
1709231200Smm	strm->next_out = lastrm->next_out;
1710231200Smm	strm->avail_out = lastrm->avail_out;
1711231200Smm	strm->total_out = lastrm->total_out;
1712231200Smm	r = deflate(strm,
1713231200Smm	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
1714231200Smm	lastrm->next_in = strm->next_in;
1715231200Smm	lastrm->avail_in = strm->avail_in;
1716231200Smm	lastrm->total_in = strm->total_in;
1717231200Smm	lastrm->next_out = strm->next_out;
1718231200Smm	lastrm->avail_out = strm->avail_out;
1719231200Smm	lastrm->total_out = strm->total_out;
1720231200Smm	switch (r) {
1721231200Smm	case Z_OK:
1722231200Smm		return (ARCHIVE_OK);
1723231200Smm	case Z_STREAM_END:
1724231200Smm		return (ARCHIVE_EOF);
1725231200Smm	default:
1726231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1727231200Smm		    "GZip compression failed:"
1728231200Smm		    " deflate() call returned status %d", r);
1729231200Smm		return (ARCHIVE_FATAL);
1730231200Smm	}
1731231200Smm}
1732231200Smm
1733231200Smmstatic int
1734231200Smmcompression_end_deflate(struct archive *a, struct la_zstream *lastrm)
1735231200Smm{
1736231200Smm	z_stream *strm;
1737231200Smm	int r;
1738231200Smm
1739231200Smm	strm = (z_stream *)lastrm->real_stream;
1740231200Smm	r = deflateEnd(strm);
1741231200Smm	free(strm);
1742231200Smm	lastrm->real_stream = NULL;
1743231200Smm	lastrm->valid = 0;
1744231200Smm	if (r != Z_OK) {
1745231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1746231200Smm		    "Failed to clean up compressor");
1747231200Smm		return (ARCHIVE_FATAL);
1748231200Smm	}
1749231200Smm	return (ARCHIVE_OK);
1750231200Smm}
1751231200Smm#else
1752231200Smmstatic int
1753231200Smmcompression_init_encoder_deflate(struct archive *a,
1754231200Smm    struct la_zstream *lastrm, int level, int withheader)
1755231200Smm{
1756231200Smm
1757231200Smm	(void) level; /* UNUSED */
1758231200Smm	(void) withheader; /* UNUSED */
1759231200Smm	if (lastrm->valid)
1760231200Smm		compression_end(a, lastrm);
1761231200Smm	return (compression_unsupported_encoder(a, lastrm, "deflate"));
1762231200Smm}
1763231200Smm#endif
1764231200Smm
1765231200Smm/*
1766231200Smm * _7_BZIP2 compressor.
1767231200Smm */
1768231200Smm#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
1769231200Smmstatic int
1770231200Smmcompression_init_encoder_bzip2(struct archive *a,
1771231200Smm    struct la_zstream *lastrm, int level)
1772231200Smm{
1773231200Smm	bz_stream *strm;
1774231200Smm
1775231200Smm	if (lastrm->valid)
1776231200Smm		compression_end(a, lastrm);
1777231200Smm	strm = calloc(1, sizeof(*strm));
1778231200Smm	if (strm == NULL) {
1779231200Smm		archive_set_error(a, ENOMEM,
1780231200Smm		    "Can't allocate memory for bzip2 stream");
1781231200Smm		return (ARCHIVE_FATAL);
1782231200Smm	}
1783231200Smm	/* bzlib.h is not const-correct, so we need this one bit
1784231200Smm	 * of ugly hackery to convert a const * pointer to
1785231200Smm	 * a non-const pointer. */
1786231200Smm	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
1787231200Smm	strm->avail_in = lastrm->avail_in;
1788231200Smm	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
1789231200Smm	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
1790231200Smm	strm->next_out = (char *)lastrm->next_out;
1791231200Smm	strm->avail_out = lastrm->avail_out;
1792231200Smm	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
1793231200Smm	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
1794231200Smm	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
1795231200Smm		free(strm);
1796231200Smm		lastrm->real_stream = NULL;
1797231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1798231200Smm		    "Internal error initializing compression library");
1799231200Smm		return (ARCHIVE_FATAL);
1800231200Smm	}
1801231200Smm	lastrm->real_stream = strm;
1802231200Smm	lastrm->valid = 1;
1803231200Smm	lastrm->code = compression_code_bzip2;
1804231200Smm	lastrm->end = compression_end_bzip2;
1805231200Smm	return (ARCHIVE_OK);
1806231200Smm}
1807231200Smm
1808231200Smmstatic int
1809231200Smmcompression_code_bzip2(struct archive *a,
1810231200Smm    struct la_zstream *lastrm, enum la_zaction action)
1811231200Smm{
1812231200Smm	bz_stream *strm;
1813231200Smm	int r;
1814231200Smm
1815231200Smm	strm = (bz_stream *)lastrm->real_stream;
1816231200Smm	/* bzlib.h is not const-correct, so we need this one bit
1817231200Smm	 * of ugly hackery to convert a const * pointer to
1818231200Smm	 * a non-const pointer. */
1819231200Smm	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
1820231200Smm	strm->avail_in = lastrm->avail_in;
1821231200Smm	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
1822231200Smm	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
1823231200Smm	strm->next_out = (char *)lastrm->next_out;
1824231200Smm	strm->avail_out = lastrm->avail_out;
1825231200Smm	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
1826231200Smm	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
1827231200Smm	r = BZ2_bzCompress(strm,
1828231200Smm	    (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
1829231200Smm	lastrm->next_in = (const unsigned char *)strm->next_in;
1830231200Smm	lastrm->avail_in = strm->avail_in;
1831231200Smm	lastrm->total_in =
1832231200Smm	    (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
1833231200Smm	    + (uint64_t)(uint32_t)strm->total_in_lo32;
1834231200Smm	lastrm->next_out = (unsigned char *)strm->next_out;
1835231200Smm	lastrm->avail_out = strm->avail_out;
1836231200Smm	lastrm->total_out =
1837231200Smm	    (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
1838231200Smm	    + (uint64_t)(uint32_t)strm->total_out_lo32;
1839231200Smm	switch (r) {
1840231200Smm	case BZ_RUN_OK:     /* Non-finishing */
1841231200Smm	case BZ_FINISH_OK:  /* Finishing: There's more work to do */
1842231200Smm		return (ARCHIVE_OK);
1843231200Smm	case BZ_STREAM_END: /* Finishing: all done */
1844231200Smm		/* Only occurs in finishing case */
1845231200Smm		return (ARCHIVE_EOF);
1846231200Smm	default:
1847231200Smm		/* Any other return value indicates an error */
1848231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1849231200Smm		    "Bzip2 compression failed:"
1850231200Smm		    " BZ2_bzCompress() call returned status %d", r);
1851231200Smm		return (ARCHIVE_FATAL);
1852231200Smm	}
1853231200Smm}
1854231200Smm
1855231200Smmstatic int
1856231200Smmcompression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
1857231200Smm{
1858231200Smm	bz_stream *strm;
1859231200Smm	int r;
1860231200Smm
1861231200Smm	strm = (bz_stream *)lastrm->real_stream;
1862231200Smm	r = BZ2_bzCompressEnd(strm);
1863231200Smm	free(strm);
1864231200Smm	lastrm->real_stream = NULL;
1865231200Smm	lastrm->valid = 0;
1866231200Smm	if (r != BZ_OK) {
1867231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1868231200Smm		    "Failed to clean up compressor");
1869231200Smm		return (ARCHIVE_FATAL);
1870231200Smm	}
1871231200Smm	return (ARCHIVE_OK);
1872231200Smm}
1873231200Smm
1874231200Smm#else
1875231200Smmstatic int
1876231200Smmcompression_init_encoder_bzip2(struct archive *a,
1877231200Smm    struct la_zstream *lastrm, int level)
1878231200Smm{
1879231200Smm
1880231200Smm	(void) level; /* UNUSED */
1881231200Smm	if (lastrm->valid)
1882231200Smm		compression_end(a, lastrm);
1883231200Smm	return (compression_unsupported_encoder(a, lastrm, "bzip2"));
1884231200Smm}
1885231200Smm#endif
1886231200Smm
1887231200Smm/*
1888231200Smm * _7_LZMA1, _7_LZMA2 compressor.
1889231200Smm */
1890231200Smm#if defined(HAVE_LZMA_H)
1891231200Smmstatic int
1892231200Smmcompression_init_encoder_lzma(struct archive *a,
1893231200Smm    struct la_zstream *lastrm, int level, uint64_t filter_id)
1894231200Smm{
1895231200Smm	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
1896231200Smm	lzma_stream *strm;
1897231200Smm	lzma_filter *lzmafilters;
1898231200Smm	lzma_options_lzma lzma_opt;
1899231200Smm	int r;
1900231200Smm
1901231200Smm	if (lastrm->valid)
1902231200Smm		compression_end(a, lastrm);
1903231200Smm	strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
1904231200Smm	if (strm == NULL) {
1905231200Smm		archive_set_error(a, ENOMEM,
1906231200Smm		    "Can't allocate memory for lzma stream");
1907231200Smm		return (ARCHIVE_FATAL);
1908231200Smm	}
1909231200Smm	lzmafilters = (lzma_filter *)(strm+1);
1910231200Smm	if (level > 6)
1911231200Smm		level = 6;
1912231200Smm	if (lzma_lzma_preset(&lzma_opt, level)) {
1913231200Smm		lastrm->real_stream = NULL;
1914231200Smm		archive_set_error(a, ENOMEM,
1915231200Smm		    "Internal error initializing compression library");
1916231200Smm		return (ARCHIVE_FATAL);
1917231200Smm	}
1918231200Smm	lzmafilters[0].id = filter_id;
1919231200Smm	lzmafilters[0].options = &lzma_opt;
1920231200Smm	lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
1921231200Smm
1922231200Smm	r = lzma_properties_size(&(lastrm->prop_size), lzmafilters);
1923231200Smm	if (r != LZMA_OK) {
1924231200Smm		free(strm);
1925231200Smm		lastrm->real_stream = NULL;
1926231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1927231200Smm		    "lzma_properties_size failed");
1928231200Smm		return (ARCHIVE_FATAL);
1929231200Smm	}
1930231200Smm	if (lastrm->prop_size) {
1931231200Smm		lastrm->props = malloc(lastrm->prop_size);
1932231200Smm		if (lastrm->props == NULL) {
1933231200Smm			free(strm);
1934231200Smm			lastrm->real_stream = NULL;
1935231200Smm			archive_set_error(a, ENOMEM,
1936231200Smm			    "Cannot allocate memory");
1937231200Smm			return (ARCHIVE_FATAL);
1938231200Smm		}
1939231200Smm		r = lzma_properties_encode(lzmafilters,  lastrm->props);
1940231200Smm		if (r != LZMA_OK) {
1941231200Smm			free(strm);
1942231200Smm			lastrm->real_stream = NULL;
1943231200Smm			archive_set_error(a, ARCHIVE_ERRNO_MISC,
1944231200Smm			    "lzma_properties_encode failed");
1945231200Smm			return (ARCHIVE_FATAL);
1946231200Smm		}
1947231200Smm	}
1948231200Smm
1949231200Smm	*strm = lzma_init_data;
1950231200Smm	r = lzma_raw_encoder(strm, lzmafilters);
1951231200Smm	switch (r) {
1952231200Smm	case LZMA_OK:
1953231200Smm		lastrm->real_stream = strm;
1954231200Smm		lastrm->valid = 1;
1955231200Smm		lastrm->code = compression_code_lzma;
1956231200Smm		lastrm->end = compression_end_lzma;
1957231200Smm		r = ARCHIVE_OK;
1958231200Smm		break;
1959231200Smm	case LZMA_MEM_ERROR:
1960231200Smm		free(strm);
1961231200Smm		lastrm->real_stream = NULL;
1962231200Smm		archive_set_error(a, ENOMEM,
1963231200Smm		    "Internal error initializing compression library: "
1964231200Smm		    "Cannot allocate memory");
1965231200Smm		r =  ARCHIVE_FATAL;
1966231200Smm		break;
1967231200Smm        default:
1968231200Smm		free(strm);
1969231200Smm		lastrm->real_stream = NULL;
1970231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1971231200Smm		    "Internal error initializing compression library: "
1972231200Smm		    "It's a bug in liblzma");
1973231200Smm		r =  ARCHIVE_FATAL;
1974231200Smm		break;
1975231200Smm	}
1976231200Smm	return (r);
1977231200Smm}
1978231200Smm
1979231200Smmstatic int
1980231200Smmcompression_init_encoder_lzma1(struct archive *a,
1981231200Smm    struct la_zstream *lastrm, int level)
1982231200Smm{
1983231200Smm	return compression_init_encoder_lzma(a, lastrm, level,
1984231200Smm		    LZMA_FILTER_LZMA1);
1985231200Smm}
1986231200Smm
1987231200Smmstatic int
1988231200Smmcompression_init_encoder_lzma2(struct archive *a,
1989231200Smm    struct la_zstream *lastrm, int level)
1990231200Smm{
1991231200Smm	return compression_init_encoder_lzma(a, lastrm, level,
1992231200Smm		    LZMA_FILTER_LZMA2);
1993231200Smm}
1994231200Smm
1995231200Smmstatic int
1996231200Smmcompression_code_lzma(struct archive *a,
1997231200Smm    struct la_zstream *lastrm, enum la_zaction action)
1998231200Smm{
1999231200Smm	lzma_stream *strm;
2000231200Smm	int r;
2001231200Smm
2002231200Smm	strm = (lzma_stream *)lastrm->real_stream;
2003231200Smm	strm->next_in = lastrm->next_in;
2004231200Smm	strm->avail_in = lastrm->avail_in;
2005231200Smm	strm->total_in = lastrm->total_in;
2006231200Smm	strm->next_out = lastrm->next_out;
2007231200Smm	strm->avail_out = lastrm->avail_out;
2008231200Smm	strm->total_out = lastrm->total_out;
2009231200Smm	r = lzma_code(strm,
2010231200Smm	    (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
2011231200Smm	lastrm->next_in = strm->next_in;
2012231200Smm	lastrm->avail_in = strm->avail_in;
2013231200Smm	lastrm->total_in = strm->total_in;
2014231200Smm	lastrm->next_out = strm->next_out;
2015231200Smm	lastrm->avail_out = strm->avail_out;
2016231200Smm	lastrm->total_out = strm->total_out;
2017231200Smm	switch (r) {
2018231200Smm	case LZMA_OK:
2019231200Smm		/* Non-finishing case */
2020231200Smm		return (ARCHIVE_OK);
2021231200Smm	case LZMA_STREAM_END:
2022231200Smm		/* This return can only occur in finishing case. */
2023231200Smm		return (ARCHIVE_EOF);
2024231200Smm	case LZMA_MEMLIMIT_ERROR:
2025231200Smm		archive_set_error(a, ENOMEM,
2026231200Smm		    "lzma compression error:"
2027231200Smm		    " %ju MiB would have been needed",
2028231200Smm		    (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
2029231200Smm			/ (1024 * 1024)));
2030231200Smm		return (ARCHIVE_FATAL);
2031231200Smm	default:
2032231200Smm		/* Any other return value indicates an error */
2033231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2034231200Smm		    "lzma compression failed:"
2035231200Smm		    " lzma_code() call returned status %d", r);
2036231200Smm		return (ARCHIVE_FATAL);
2037231200Smm	}
2038231200Smm}
2039231200Smm
2040231200Smmstatic int
2041231200Smmcompression_end_lzma(struct archive *a, struct la_zstream *lastrm)
2042231200Smm{
2043231200Smm	lzma_stream *strm;
2044231200Smm
2045231200Smm	(void)a; /* UNUSED */
2046231200Smm	strm = (lzma_stream *)lastrm->real_stream;
2047231200Smm	lzma_end(strm);
2048231200Smm	free(strm);
2049231200Smm	lastrm->valid = 0;
2050231200Smm	lastrm->real_stream = NULL;
2051231200Smm	return (ARCHIVE_OK);
2052231200Smm}
2053231200Smm#else
2054231200Smmstatic int
2055231200Smmcompression_init_encoder_lzma1(struct archive *a,
2056231200Smm    struct la_zstream *lastrm, int level)
2057231200Smm{
2058231200Smm
2059231200Smm	(void) level; /* UNUSED */
2060231200Smm	if (lastrm->valid)
2061231200Smm		compression_end(a, lastrm);
2062231200Smm	return (compression_unsupported_encoder(a, lastrm, "lzma"));
2063231200Smm}
2064231200Smmstatic int
2065231200Smmcompression_init_encoder_lzma2(struct archive *a,
2066231200Smm    struct la_zstream *lastrm, int level)
2067231200Smm{
2068231200Smm
2069231200Smm	(void) level; /* UNUSED */
2070231200Smm	if (lastrm->valid)
2071231200Smm		compression_end(a, lastrm);
2072231200Smm	return (compression_unsupported_encoder(a, lastrm, "lzma"));
2073231200Smm}
2074231200Smm#endif
2075231200Smm
2076231200Smm/*
2077231200Smm * _7_PPMD compressor.
2078231200Smm */
2079231200Smmstatic void *
2080231200Smmppmd_alloc(void *p, size_t size)
2081231200Smm{
2082231200Smm	(void)p;
2083231200Smm	return malloc(size);
2084231200Smm}
2085231200Smmstatic void
2086231200Smmppmd_free(void *p, void *address)
2087231200Smm{
2088231200Smm	(void)p;
2089231200Smm	free(address);
2090231200Smm}
2091231200Smmstatic ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
2092231200Smmstatic void
2093231200Smmppmd_write(void *p, Byte b)
2094231200Smm{
2095231200Smm	struct archive_write *a = ((IByteOut *)p)->a;
2096231200Smm	struct _7zip *zip = (struct _7zip *)(a->format_data);
2097231200Smm	struct la_zstream *lastrm = &(zip->stream);
2098231200Smm	struct ppmd_stream *strm;
2099231200Smm
2100231200Smm	if (lastrm->avail_out) {
2101231200Smm		*lastrm->next_out++ = b;
2102231200Smm		lastrm->avail_out--;
2103231200Smm		lastrm->total_out++;
2104231200Smm		return;
2105231200Smm	}
2106231200Smm	strm = (struct ppmd_stream *)lastrm->real_stream;
2107231200Smm	if (strm->buff_ptr < strm->buff_end) {
2108231200Smm		*strm->buff_ptr++ = b;
2109231200Smm		strm->buff_bytes++;
2110231200Smm	}
2111231200Smm}
2112231200Smm
2113231200Smmstatic int
2114231200Smmcompression_init_encoder_ppmd(struct archive *a,
2115231200Smm    struct la_zstream *lastrm, unsigned maxOrder, uint32_t msize)
2116231200Smm{
2117231200Smm	struct ppmd_stream *strm;
2118231200Smm	uint8_t *props;
2119231200Smm	int r;
2120231200Smm
2121231200Smm	if (lastrm->valid)
2122231200Smm		compression_end(a, lastrm);
2123231200Smm	strm = calloc(1, sizeof(*strm));
2124231200Smm	if (strm == NULL) {
2125231200Smm		archive_set_error(a, ENOMEM,
2126231200Smm		    "Can't allocate memory for PPMd");
2127231200Smm		return (ARCHIVE_FATAL);
2128231200Smm	}
2129231200Smm	strm->buff = malloc(32);
2130231200Smm	if (strm->buff == NULL) {
2131231200Smm		free(strm);
2132231200Smm		archive_set_error(a, ENOMEM,
2133231200Smm		    "Can't allocate memory for PPMd");
2134231200Smm		return (ARCHIVE_FATAL);
2135231200Smm	}
2136231200Smm	strm->buff_ptr = strm->buff;
2137231200Smm	strm->buff_end = strm->buff + 32;
2138231200Smm
2139231200Smm	props = malloc(1+4);
2140231200Smm	if (props == NULL) {
2141231200Smm		free(strm->buff);
2142231200Smm		free(strm);
2143231200Smm		archive_set_error(a, ENOMEM,
2144231200Smm		    "Coludn't allocate memory for PPMd");
2145231200Smm		return (ARCHIVE_FATAL);
2146231200Smm	}
2147231200Smm	props[0] = maxOrder;
2148231200Smm	archive_le32enc(props+1, msize);
2149231200Smm	__archive_ppmd7_functions.Ppmd7_Construct(&strm->ppmd7_context);
2150231200Smm	r = __archive_ppmd7_functions.Ppmd7_Alloc(
2151231200Smm		&strm->ppmd7_context, msize, &g_szalloc);
2152231200Smm	if (r == 0) {
2153231200Smm		free(strm->buff);
2154231200Smm		free(strm);
2155231200Smm		free(props);
2156231200Smm		archive_set_error(a, ENOMEM,
2157231200Smm		    "Coludn't allocate memory for PPMd");
2158231200Smm		return (ARCHIVE_FATAL);
2159231200Smm	}
2160231200Smm	__archive_ppmd7_functions.Ppmd7_Init(&(strm->ppmd7_context), maxOrder);
2161231200Smm	strm->byteout.a = (struct archive_write *)a;
2162231200Smm	strm->byteout.Write = ppmd_write;
2163231200Smm	strm->range_enc.Stream = &(strm->byteout);
2164231200Smm	__archive_ppmd7_functions.Ppmd7z_RangeEnc_Init(&(strm->range_enc));
2165231200Smm	strm->stat = 0;
2166231200Smm
2167231200Smm	lastrm->real_stream = strm;
2168231200Smm	lastrm->valid = 1;
2169231200Smm	lastrm->code = compression_code_ppmd;
2170231200Smm	lastrm->end = compression_end_ppmd;
2171231200Smm	lastrm->prop_size = 5;
2172231200Smm	lastrm->props = props;
2173231200Smm	return (ARCHIVE_OK);
2174231200Smm}
2175231200Smm
2176231200Smmstatic int
2177231200Smmcompression_code_ppmd(struct archive *a,
2178231200Smm    struct la_zstream *lastrm, enum la_zaction action)
2179231200Smm{
2180231200Smm	struct ppmd_stream *strm;
2181231200Smm
2182231200Smm	strm = (struct ppmd_stream *)lastrm->real_stream;
2183231200Smm
2184231200Smm	/* Copy encoded data if there are remaining bytes from previous call. */
2185231200Smm	if (strm->buff_bytes) {
2186231200Smm		uint8_t *p = strm->buff_ptr - strm->buff_bytes;
2187231200Smm		while (lastrm->avail_out && strm->buff_bytes) {
2188231200Smm			*lastrm->next_out++ = *p++;
2189231200Smm			lastrm->avail_out--;
2190231200Smm			lastrm->total_out++;
2191231200Smm			strm->buff_bytes--;
2192231200Smm		}
2193231200Smm		if (strm->buff_bytes)
2194231200Smm			return (ARCHIVE_OK);
2195231200Smm		if (strm->stat == 1)
2196231200Smm			return (ARCHIVE_EOF);
2197231200Smm		strm->buff_ptr = strm->buff;
2198231200Smm	}
2199231200Smm	while (lastrm->avail_in && lastrm->avail_out) {
2200231200Smm		__archive_ppmd7_functions.Ppmd7_EncodeSymbol(
2201231200Smm			&(strm->ppmd7_context), &(strm->range_enc),
2202231200Smm			*lastrm->next_in++);
2203231200Smm		lastrm->avail_in--;
2204231200Smm		lastrm->total_in++;
2205231200Smm	}
2206231200Smm	if (lastrm->avail_in == 0 && action == ARCHIVE_Z_FINISH) {
2207231200Smm		__archive_ppmd7_functions.Ppmd7z_RangeEnc_FlushData(
2208231200Smm			&(strm->range_enc));
2209231200Smm		strm->stat = 1;
2210231200Smm		/* Return EOF if there are no remaining bytes. */
2211231200Smm		if (strm->buff_bytes == 0)
2212231200Smm			return (ARCHIVE_EOF);
2213231200Smm	}
2214231200Smm	return (ARCHIVE_OK);
2215231200Smm}
2216231200Smm
2217231200Smmstatic int
2218231200Smmcompression_end_ppmd(struct archive *a, struct la_zstream *lastrm)
2219231200Smm{
2220231200Smm	struct ppmd_stream *strm;
2221231200Smm
2222231200Smm	strm = (struct ppmd_stream *)lastrm->real_stream;
2223231200Smm	__archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context, &g_szalloc);
2224231200Smm	free(strm->buff);
2225231200Smm	free(strm);
2226231200Smm	lastrm->real_stream = NULL;
2227231200Smm	lastrm->valid = 0;
2228231200Smm	return (ARCHIVE_OK);
2229231200Smm}
2230231200Smm
2231231200Smm/*
2232231200Smm * Universal compressor initializer.
2233231200Smm */
2234231200Smmstatic int
2235231200Smm_7z_compression_init_encoder(struct archive_write *a, unsigned compression,
2236231200Smm    int compression_level)
2237231200Smm{
2238231200Smm	struct _7zip *zip;
2239231200Smm	int r;
2240231200Smm
2241231200Smm	zip = (struct _7zip *)a->format_data;
2242231200Smm	switch (compression) {
2243231200Smm	case _7Z_DEFLATE:
2244231200Smm		r = compression_init_encoder_deflate(
2245231200Smm		    &(a->archive), &(zip->stream),
2246231200Smm		    compression_level, 0);
2247231200Smm		break;
2248231200Smm	case _7Z_BZIP2:
2249231200Smm		r = compression_init_encoder_bzip2(
2250231200Smm		    &(a->archive), &(zip->stream),
2251231200Smm		    compression_level);
2252231200Smm		break;
2253231200Smm	case _7Z_LZMA1:
2254231200Smm		r = compression_init_encoder_lzma1(
2255231200Smm		    &(a->archive), &(zip->stream),
2256231200Smm		    compression_level);
2257231200Smm		break;
2258231200Smm	case _7Z_LZMA2:
2259231200Smm		r = compression_init_encoder_lzma2(
2260231200Smm		    &(a->archive), &(zip->stream),
2261231200Smm		    compression_level);
2262231200Smm		break;
2263231200Smm	case _7Z_PPMD:
2264231200Smm		r = compression_init_encoder_ppmd(
2265231200Smm		    &(a->archive), &(zip->stream),
2266231200Smm		    PPMD7_DEFAULT_ORDER, PPMD7_DEFAULT_MEM_SIZE);
2267231200Smm		break;
2268231200Smm	case _7Z_COPY:
2269231200Smm	default:
2270231200Smm		r = compression_init_encoder_copy(
2271231200Smm		    &(a->archive), &(zip->stream));
2272231200Smm		break;
2273231200Smm	}
2274231200Smm	if (r == ARCHIVE_OK) {
2275231200Smm		zip->stream.total_in = 0;
2276231200Smm		zip->stream.next_out = zip->wbuff;
2277231200Smm		zip->stream.avail_out = sizeof(zip->wbuff);
2278231200Smm		zip->stream.total_out = 0;
2279231200Smm	}
2280231200Smm
2281231200Smm	return (r);
2282231200Smm}
2283231200Smm
2284231200Smmstatic int
2285231200Smmcompression_code(struct archive *a, struct la_zstream *lastrm,
2286231200Smm    enum la_zaction action)
2287231200Smm{
2288231200Smm	if (lastrm->valid)
2289231200Smm		return (lastrm->code(a, lastrm, action));
2290231200Smm	return (ARCHIVE_OK);
2291231200Smm}
2292231200Smm
2293231200Smmstatic int
2294231200Smmcompression_end(struct archive *a, struct la_zstream *lastrm)
2295231200Smm{
2296231200Smm	if (lastrm->valid) {
2297231200Smm		lastrm->prop_size = 0;
2298231200Smm		free(lastrm->props);
2299231200Smm		lastrm->props = NULL;
2300231200Smm		return (lastrm->end(a, lastrm));
2301231200Smm	}
2302231200Smm	return (ARCHIVE_OK);
2303231200Smm}
2304231200Smm
2305231200Smm
2306