archive_write_set_format_7zip.c revision 328827
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	 */
202238856Smm	unsigned char		 wbuff[512 * 20 * 6];
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.
208311041Smm	 * We use 'next' (a member 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,
388248616Smm			    "Unknown 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,
408248616Smm			    "Illegal value `%s'",
409231200Smm			    value);
410231200Smm			return (ARCHIVE_FAILED);
411231200Smm		}
412231200Smm		zip->opt_compression_level = value[0] - '0';
413231200Smm		return (ARCHIVE_OK);
414231200Smm	}
415231200Smm
416232153Smm	/* Note: The "warn" return is just to inform the options
417232153Smm	 * supervisor that we didn't handle it.  It will generate
418232153Smm	 * a suitable error if no one used this option. */
419232153Smm	return (ARCHIVE_WARN);
420231200Smm}
421231200Smm
422231200Smmstatic int
423231200Smm_7z_write_header(struct archive_write *a, struct archive_entry *entry)
424231200Smm{
425231200Smm	struct _7zip *zip;
426231200Smm	struct file *file;
427231200Smm	int r;
428231200Smm
429231200Smm	zip = (struct _7zip *)a->format_data;
430231200Smm	zip->cur_file = NULL;
431231200Smm	zip->entry_bytes_remaining = 0;
432231200Smm
433231200Smm	if (zip->sconv == NULL) {
434231200Smm		zip->sconv = archive_string_conversion_to_charset(
435231200Smm		    &a->archive, "UTF-16LE", 1);
436231200Smm		if (zip->sconv == NULL)
437231200Smm			return (ARCHIVE_FATAL);
438231200Smm	}
439231200Smm
440231200Smm	r = file_new(a, entry, &file);
441231200Smm	if (r < ARCHIVE_WARN) {
442231200Smm		file_free(file);
443231200Smm		return (r);
444231200Smm	}
445248616Smm	if (file->size == 0 && file->dir) {
446248616Smm		if (!__archive_rb_tree_insert_node(&(zip->rbtree),
447248616Smm		    (struct archive_rb_node *)file)) {
448248616Smm			/* We have already had the same file. */
449248616Smm			file_free(file);
450248616Smm			return (ARCHIVE_OK);
451248616Smm		}
452248616Smm	}
453231200Smm
454231200Smm	if (file->flg & MTIME_IS_SET)
455231200Smm		zip->total_number_time_defined[MTIME]++;
456231200Smm	if (file->flg & CTIME_IS_SET)
457231200Smm		zip->total_number_time_defined[CTIME]++;
458231200Smm	if (file->flg & ATIME_IS_SET)
459231200Smm		zip->total_number_time_defined[ATIME]++;
460231200Smm
461231200Smm	zip->total_number_entry++;
462231200Smm	zip->total_bytes_entry_name += file->name_len + 2;
463231200Smm	if (file->size == 0) {
464231200Smm		/* Count up the number of empty files. */
465231200Smm		zip->total_number_empty_entry++;
466231200Smm		if (file->dir)
467231200Smm			zip->total_number_dir_entry++;
468231200Smm		else
469231200Smm			file_register_empty(zip, file);
470231200Smm		return (r);
471231200Smm	}
472231200Smm
473231200Smm	/*
474231200Smm	 * Init compression.
475231200Smm	 */
476231200Smm	if ((zip->total_number_entry - zip->total_number_empty_entry) == 1) {
477231200Smm		r = _7z_compression_init_encoder(a, zip->opt_compression,
478231200Smm			zip->opt_compression_level);
479231200Smm		if (r < 0) {
480231200Smm			file_free(file);
481231200Smm			return (ARCHIVE_FATAL);
482231200Smm		}
483231200Smm	}
484231200Smm
485231200Smm	/* Register a non-empty file. */
486231200Smm	file_register(zip, file);
487231200Smm
488231200Smm	/*
489231200Smm	 * Set the current file to cur_file to read its contents.
490231200Smm	 */
491231200Smm	zip->cur_file = file;
492231200Smm
493231200Smm
494231200Smm	/* Save a offset of current file in temporary file. */
495231200Smm	zip->entry_bytes_remaining = file->size;
496231200Smm	zip->entry_crc32 = 0;
497231200Smm
498231200Smm	/*
499231200Smm	 * Store a symbolic link name as file contents.
500231200Smm	 */
501231200Smm	if (archive_entry_filetype(entry) == AE_IFLNK) {
502231200Smm		ssize_t bytes;
503231200Smm		const void *p = (const void *)archive_entry_symlink(entry);
504238856Smm		bytes = compress_out(a, p, (size_t)file->size, ARCHIVE_Z_RUN);
505231200Smm		if (bytes < 0)
506231200Smm			return ((int)bytes);
507248616Smm		zip->entry_crc32 = crc32(zip->entry_crc32, p, (unsigned)bytes);
508231200Smm		zip->entry_bytes_remaining -= bytes;
509231200Smm	}
510231200Smm
511231200Smm	return (r);
512231200Smm}
513231200Smm
514231200Smm/*
515231200Smm * Write data to a temporary file.
516231200Smm */
517231200Smmstatic int
518231200Smmwrite_to_temp(struct archive_write *a, const void *buff, size_t s)
519231200Smm{
520231200Smm	struct _7zip *zip;
521232153Smm	const unsigned char *p;
522231200Smm	ssize_t ws;
523231200Smm
524231200Smm	zip = (struct _7zip *)a->format_data;
525231200Smm
526231200Smm	/*
527231200Smm	 * Open a temporary file.
528231200Smm	 */
529231200Smm	if (zip->temp_fd == -1) {
530231200Smm		zip->temp_offset = 0;
531231200Smm		zip->temp_fd = __archive_mktemp(NULL);
532231200Smm		if (zip->temp_fd < 0) {
533231200Smm			archive_set_error(&a->archive, errno,
534231200Smm			    "Couldn't create temporary file");
535231200Smm			return (ARCHIVE_FATAL);
536231200Smm		}
537231200Smm	}
538231200Smm
539232153Smm	p = (const unsigned char *)buff;
540231200Smm	while (s) {
541231200Smm		ws = write(zip->temp_fd, p, s);
542231200Smm		if (ws < 0) {
543231200Smm			archive_set_error(&(a->archive), errno,
544231200Smm			    "fwrite function failed");
545231200Smm			return (ARCHIVE_FATAL);
546231200Smm		}
547231200Smm		s -= ws;
548231200Smm		p += ws;
549231200Smm		zip->temp_offset += ws;
550231200Smm	}
551231200Smm	return (ARCHIVE_OK);
552231200Smm}
553231200Smm
554231200Smmstatic ssize_t
555231200Smmcompress_out(struct archive_write *a, const void *buff, size_t s,
556231200Smm    enum la_zaction run)
557231200Smm{
558231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
559231200Smm	int r;
560231200Smm
561231200Smm	if (run == ARCHIVE_Z_FINISH && zip->stream.total_in == 0 && s == 0)
562231200Smm		return (0);
563231200Smm
564231200Smm	if ((zip->crc32flg & PRECODE_CRC32) && s)
565248616Smm		zip->precode_crc32 = crc32(zip->precode_crc32, buff,
566248616Smm		    (unsigned)s);
567231200Smm	zip->stream.next_in = (const unsigned char *)buff;
568231200Smm	zip->stream.avail_in = s;
569248616Smm	for (;;) {
570231200Smm		/* Compress file data. */
571231200Smm		r = compression_code(&(a->archive), &(zip->stream), run);
572231200Smm		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
573231200Smm			return (ARCHIVE_FATAL);
574231200Smm		if (zip->stream.avail_out == 0) {
575231200Smm			if (write_to_temp(a, zip->wbuff, sizeof(zip->wbuff))
576231200Smm			    != ARCHIVE_OK)
577231200Smm				return (ARCHIVE_FATAL);
578231200Smm			zip->stream.next_out = zip->wbuff;
579231200Smm			zip->stream.avail_out = sizeof(zip->wbuff);
580231200Smm			if (zip->crc32flg & ENCODED_CRC32)
581231200Smm				zip->encoded_crc32 = crc32(zip->encoded_crc32,
582231200Smm				    zip->wbuff, sizeof(zip->wbuff));
583248616Smm			if (run == ARCHIVE_Z_FINISH && r != ARCHIVE_EOF)
584248616Smm				continue;
585231200Smm		}
586248616Smm		if (zip->stream.avail_in == 0)
587248616Smm			break;
588248616Smm	}
589231200Smm	if (run == ARCHIVE_Z_FINISH) {
590231200Smm		uint64_t bytes = sizeof(zip->wbuff) - zip->stream.avail_out;
591238856Smm		if (write_to_temp(a, zip->wbuff, (size_t)bytes) != ARCHIVE_OK)
592231200Smm			return (ARCHIVE_FATAL);
593231200Smm		if ((zip->crc32flg & ENCODED_CRC32) && bytes)
594231200Smm			zip->encoded_crc32 = crc32(zip->encoded_crc32,
595238856Smm			    zip->wbuff, (unsigned)bytes);
596231200Smm	}
597231200Smm
598231200Smm	return (s);
599231200Smm}
600231200Smm
601231200Smmstatic ssize_t
602231200Smm_7z_write_data(struct archive_write *a, const void *buff, size_t s)
603231200Smm{
604231200Smm	struct _7zip *zip;
605231200Smm	ssize_t bytes;
606231200Smm
607231200Smm	zip = (struct _7zip *)a->format_data;
608231200Smm
609231200Smm	if (s > zip->entry_bytes_remaining)
610238856Smm		s = (size_t)zip->entry_bytes_remaining;
611231200Smm	if (s == 0 || zip->cur_file == NULL)
612231200Smm		return (0);
613231200Smm	bytes = compress_out(a, buff, s, ARCHIVE_Z_RUN);
614231200Smm	if (bytes < 0)
615231200Smm		return (bytes);
616248616Smm	zip->entry_crc32 = crc32(zip->entry_crc32, buff, (unsigned)bytes);
617231200Smm	zip->entry_bytes_remaining -= bytes;
618231200Smm	return (bytes);
619231200Smm}
620231200Smm
621231200Smmstatic int
622231200Smm_7z_finish_entry(struct archive_write *a)
623231200Smm{
624231200Smm	struct _7zip *zip;
625231200Smm	size_t s;
626231200Smm	ssize_t r;
627231200Smm
628231200Smm	zip = (struct _7zip *)a->format_data;
629231200Smm	if (zip->cur_file == NULL)
630231200Smm		return (ARCHIVE_OK);
631231200Smm
632231200Smm	while (zip->entry_bytes_remaining > 0) {
633238856Smm		s = (size_t)zip->entry_bytes_remaining;
634231200Smm		if (s > a->null_length)
635231200Smm			s = a->null_length;
636231200Smm		r = _7z_write_data(a, a->nulls, s);
637231200Smm		if (r < 0)
638248616Smm			return ((int)r);
639231200Smm	}
640231200Smm	zip->total_bytes_compressed += zip->stream.total_in;
641231200Smm	zip->total_bytes_uncompressed += zip->stream.total_out;
642231200Smm	zip->cur_file->crc32 = zip->entry_crc32;
643231200Smm	zip->cur_file = NULL;
644231200Smm
645231200Smm	return (ARCHIVE_OK);
646231200Smm}
647231200Smm
648231200Smmstatic int
649231200Smmflush_wbuff(struct archive_write *a)
650231200Smm{
651231200Smm	struct _7zip *zip;
652231200Smm	int r;
653231200Smm	size_t s;
654231200Smm
655231200Smm	zip = (struct _7zip *)a->format_data;
656231200Smm	s = sizeof(zip->wbuff) - zip->wbuff_remaining;
657231200Smm	r = __archive_write_output(a, zip->wbuff, s);
658231200Smm	if (r != ARCHIVE_OK)
659231200Smm		return (r);
660231200Smm	zip->wbuff_remaining = sizeof(zip->wbuff);
661231200Smm	return (r);
662231200Smm}
663231200Smm
664231200Smmstatic int
665231200Smmcopy_out(struct archive_write *a, uint64_t offset, uint64_t length)
666231200Smm{
667231200Smm	struct _7zip *zip;
668231200Smm	int r;
669231200Smm
670231200Smm	zip = (struct _7zip *)a->format_data;
671231200Smm	if (zip->temp_offset > 0 &&
672231200Smm	    lseek(zip->temp_fd, offset, SEEK_SET) < 0) {
673231200Smm		archive_set_error(&(a->archive), errno, "lseek failed");
674231200Smm		return (ARCHIVE_FATAL);
675231200Smm	}
676231200Smm	while (length) {
677231200Smm		size_t rsize;
678231200Smm		ssize_t rs;
679231200Smm		unsigned char *wb;
680231200Smm
681231200Smm		if (length > zip->wbuff_remaining)
682231200Smm			rsize = zip->wbuff_remaining;
683231200Smm		else
684231200Smm			rsize = (size_t)length;
685231200Smm		wb = zip->wbuff + (sizeof(zip->wbuff) - zip->wbuff_remaining);
686231200Smm		rs = read(zip->temp_fd, wb, rsize);
687231200Smm		if (rs < 0) {
688231200Smm			archive_set_error(&(a->archive), errno,
689231200Smm			    "Can't read temporary file(%jd)",
690231200Smm			    (intmax_t)rs);
691231200Smm			return (ARCHIVE_FATAL);
692231200Smm		}
693231200Smm		if (rs == 0) {
694231200Smm			archive_set_error(&(a->archive), 0,
695231200Smm			    "Truncated 7-Zip archive");
696231200Smm			return (ARCHIVE_FATAL);
697231200Smm		}
698231200Smm		zip->wbuff_remaining -= rs;
699231200Smm		length -= rs;
700231200Smm		if (zip->wbuff_remaining == 0) {
701231200Smm			r = flush_wbuff(a);
702231200Smm			if (r != ARCHIVE_OK)
703231200Smm				return (r);
704231200Smm		}
705231200Smm	}
706231200Smm	return (ARCHIVE_OK);
707231200Smm}
708231200Smm
709231200Smmstatic int
710231200Smm_7z_close(struct archive_write *a)
711231200Smm{
712231200Smm	struct _7zip *zip;
713231200Smm	unsigned char *wb;
714231200Smm	uint64_t header_offset, header_size, header_unpacksize;
715231200Smm	uint64_t length;
716231200Smm	uint32_t header_crc32;
717231200Smm	int r;
718231200Smm
719231200Smm	zip = (struct _7zip *)a->format_data;
720231200Smm
721231200Smm	if (zip->total_number_entry > 0) {
722231200Smm		struct archive_rb_node *n;
723231200Smm		uint64_t data_offset, data_size, data_unpacksize;
724231200Smm		unsigned header_compression;
725231200Smm
726231200Smm		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
727231200Smm		if (r < 0)
728231200Smm			return (r);
729231200Smm		data_offset = 0;
730231200Smm		data_size = zip->stream.total_out;
731231200Smm		data_unpacksize = zip->stream.total_in;
732231200Smm		zip->coder.codec = zip->opt_compression;
733231200Smm		zip->coder.prop_size = zip->stream.prop_size;
734231200Smm		zip->coder.props = zip->stream.props;
735231200Smm		zip->stream.prop_size = 0;
736231200Smm		zip->stream.props = NULL;
737231200Smm		zip->total_number_nonempty_entry =
738231200Smm		    zip->total_number_entry - zip->total_number_empty_entry;
739231200Smm
740231200Smm		/* Connect an empty file list. */
741231200Smm		if (zip->empty_list.first != NULL) {
742231200Smm			*zip->file_list.last = zip->empty_list.first;
743231200Smm			zip->file_list.last = zip->empty_list.last;
744231200Smm		}
745231200Smm		/* Connect a directory file list. */
746231200Smm		ARCHIVE_RB_TREE_FOREACH(n, &(zip->rbtree)) {
747231200Smm			file_register(zip, (struct file *)n);
748231200Smm		}
749231200Smm
750231200Smm		/*
751231200Smm		 * NOTE: 7z command supports just LZMA1, LZMA2 and COPY for
752231200Smm		 * the compression type for encoding the header.
753231200Smm		 */
754231200Smm#if HAVE_LZMA_H
755231200Smm		header_compression = _7Z_LZMA1;
756231200Smm		/* If the stored file is only one, do not encode the header.
757231200Smm		 * This is the same way 7z command does. */
758231200Smm		if (zip->total_number_entry == 1)
759231200Smm			header_compression = _7Z_COPY;
760231200Smm#else
761231200Smm		header_compression = _7Z_COPY;
762231200Smm#endif
763231200Smm		r = _7z_compression_init_encoder(a, header_compression, 6);
764231200Smm		if (r < 0)
765231200Smm			return (r);
766231200Smm		zip->crc32flg = PRECODE_CRC32;
767231200Smm		zip->precode_crc32 = 0;
768231200Smm		r = make_header(a, data_offset, data_size, data_unpacksize,
769231200Smm			1, &(zip->coder));
770231200Smm		if (r < 0)
771231200Smm			return (r);
772231200Smm		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
773231200Smm		if (r < 0)
774231200Smm			return (r);
775231200Smm		header_offset = data_offset + data_size;
776231200Smm		header_size = zip->stream.total_out;
777231200Smm		header_crc32 = zip->precode_crc32;
778231200Smm		header_unpacksize = zip->stream.total_in;
779231200Smm
780231200Smm		if (header_compression != _7Z_COPY) {
781231200Smm			/*
782231200Smm			 * Encode the header in order to reduce the size
783231200Smm			 * of the archive.
784231200Smm			 */
785231200Smm			free(zip->coder.props);
786231200Smm			zip->coder.codec = header_compression;
787231200Smm			zip->coder.prop_size = zip->stream.prop_size;
788231200Smm			zip->coder.props = zip->stream.props;
789231200Smm			zip->stream.prop_size = 0;
790231200Smm			zip->stream.props = NULL;
791231200Smm
792231200Smm			r = _7z_compression_init_encoder(a, _7Z_COPY, 0);
793231200Smm			if (r < 0)
794231200Smm				return (r);
795231200Smm			zip->crc32flg = ENCODED_CRC32;
796231200Smm			zip->encoded_crc32 = 0;
797231200Smm
798231200Smm			/*
799231200Smm			 * Make EncodedHeader.
800231200Smm			 */
801231200Smm			r = enc_uint64(a, kEncodedHeader);
802231200Smm			if (r < 0)
803231200Smm				return (r);
804231200Smm			r = make_streamsInfo(a, header_offset, header_size,
805231200Smm			      header_unpacksize, 1, &(zip->coder), 0,
806231200Smm			      header_crc32);
807231200Smm			if (r < 0)
808231200Smm				return (r);
809231200Smm			r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
810231200Smm			if (r < 0)
811231200Smm				return (r);
812231200Smm			header_offset = header_offset + header_size;
813231200Smm			header_size = zip->stream.total_out;
814231200Smm			header_crc32 = zip->encoded_crc32;
815231200Smm		}
816231200Smm		zip->crc32flg = 0;
817231200Smm	} else {
818231200Smm		header_offset = header_size = 0;
819231200Smm		header_crc32 = 0;
820231200Smm	}
821231200Smm
822231200Smm	length = zip->temp_offset;
823231200Smm
824231200Smm	/*
825231200Smm	 * Make the zip header on wbuff(write buffer).
826231200Smm	 */
827231200Smm	wb = zip->wbuff;
828231200Smm	zip->wbuff_remaining = sizeof(zip->wbuff);
829231200Smm	memcpy(&wb[0], "7z\xBC\xAF\x27\x1C", 6);
830231200Smm	wb[6] = 0;/* Major version. */
831231200Smm	wb[7] = 3;/* Minor version. */
832231200Smm	archive_le64enc(&wb[12], header_offset);/* Next Header Offset */
833231200Smm	archive_le64enc(&wb[20], header_size);/* Next Header Size */
834231200Smm	archive_le32enc(&wb[28], header_crc32);/* Next Header CRC */
835231200Smm	archive_le32enc(&wb[8], crc32(0, &wb[12], 20));/* Start Header CRC */
836231200Smm	zip->wbuff_remaining -= 32;
837231200Smm
838231200Smm	/*
839231200Smm	 * Read all file contents and an encoded header from the temporary
840231200Smm	 * file and write out it.
841231200Smm	 */
842231200Smm	r = copy_out(a, 0, length);
843231200Smm	if (r != ARCHIVE_OK)
844231200Smm		return (r);
845231200Smm	r = flush_wbuff(a);
846231200Smm	return (r);
847231200Smm}
848231200Smm
849231200Smm/*
850231200Smm * Encode 64 bits value into 7-Zip's encoded UINT64 value.
851231200Smm */
852231200Smmstatic int
853231200Smmenc_uint64(struct archive_write *a, uint64_t val)
854231200Smm{
855231200Smm	unsigned mask = 0x80;
856231200Smm	uint8_t numdata[9];
857231200Smm	int i;
858231200Smm
859231200Smm	numdata[0] = 0;
860232153Smm	for (i = 1; i < (int)sizeof(numdata); i++) {
861231200Smm		if (val < mask) {
862231200Smm			numdata[0] |= (uint8_t)val;
863231200Smm			break;
864231200Smm		}
865231200Smm		numdata[i] = (uint8_t)val;
866231200Smm		val >>= 8;
867231200Smm		numdata[0] |= mask;
868231200Smm		mask >>= 1;
869231200Smm	}
870248616Smm	return ((int)compress_out(a, numdata, i, ARCHIVE_Z_RUN));
871231200Smm}
872231200Smm
873231200Smmstatic int
874231200Smmmake_substreamsInfo(struct archive_write *a, struct coder *coders)
875231200Smm{
876231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
877231200Smm	struct file *file;
878231200Smm	int r;
879231200Smm
880231200Smm	/*
881231200Smm	 * Make SubStreamsInfo.
882231200Smm	 */
883231200Smm	r = enc_uint64(a, kSubStreamsInfo);
884231200Smm	if (r < 0)
885231200Smm		return (r);
886231200Smm
887231200Smm	if (zip->total_number_nonempty_entry > 1 && coders->codec != _7Z_COPY) {
888231200Smm		/*
889231200Smm		 * Make NumUnPackStream.
890231200Smm		 */
891231200Smm		r = enc_uint64(a, kNumUnPackStream);
892231200Smm		if (r < 0)
893231200Smm			return (r);
894231200Smm
895231200Smm		/* Write numUnpackStreams */
896231200Smm		r = enc_uint64(a, zip->total_number_nonempty_entry);
897231200Smm		if (r < 0)
898231200Smm			return (r);
899231200Smm
900231200Smm		/*
901231200Smm		 * Make kSize.
902231200Smm		 */
903231200Smm		r = enc_uint64(a, kSize);
904231200Smm		if (r < 0)
905231200Smm			return (r);
906231200Smm		file = zip->file_list.first;
907231200Smm		for (;file != NULL; file = file->next) {
908231200Smm			if (file->next == NULL ||
909231200Smm			    file->next->size == 0)
910231200Smm				break;
911231200Smm			r = enc_uint64(a, file->size);
912231200Smm			if (r < 0)
913231200Smm				return (r);
914231200Smm		}
915231200Smm	}
916231200Smm
917231200Smm	/*
918231200Smm	 * Make CRC.
919231200Smm	 */
920231200Smm	r = enc_uint64(a, kCRC);
921231200Smm	if (r < 0)
922231200Smm		return (r);
923231200Smm
924231200Smm
925231200Smm	/* All are defined */
926231200Smm	r = enc_uint64(a, 1);
927231200Smm	if (r < 0)
928231200Smm		return (r);
929231200Smm	file = zip->file_list.first;
930231200Smm	for (;file != NULL; file = file->next) {
931231200Smm		uint8_t crc[4];
932231200Smm		if (file->size == 0)
933231200Smm			break;
934231200Smm		archive_le32enc(crc, file->crc32);
935248616Smm		r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
936231200Smm		if (r < 0)
937231200Smm			return (r);
938231200Smm	}
939231200Smm
940231200Smm	/* Write End. */
941231200Smm	r = enc_uint64(a, kEnd);
942231200Smm	if (r < 0)
943231200Smm		return (r);
944231200Smm	return (ARCHIVE_OK);
945231200Smm}
946231200Smm
947231200Smmstatic int
948231200Smmmake_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
949231200Smm    uint64_t unpack_size, int num_coder, struct coder *coders, int substrm,
950231200Smm    uint32_t header_crc)
951231200Smm{
952231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
953231200Smm	uint8_t codec_buff[8];
954231200Smm	int numFolders, fi;
955231200Smm	int codec_size;
956231200Smm	int i, r;
957231200Smm
958231200Smm	if (coders->codec == _7Z_COPY)
959248616Smm		numFolders = (int)zip->total_number_nonempty_entry;
960231200Smm	else
961231200Smm		numFolders = 1;
962231200Smm
963231200Smm	/*
964231200Smm	 * Make PackInfo.
965231200Smm	 */
966231200Smm	r = enc_uint64(a, kPackInfo);
967231200Smm	if (r < 0)
968231200Smm		return (r);
969231200Smm
970231200Smm	/* Write PackPos. */
971231200Smm	r = enc_uint64(a, offset);
972231200Smm	if (r < 0)
973231200Smm		return (r);
974231200Smm
975231200Smm	/* Write NumPackStreams. */
976231200Smm	r = enc_uint64(a, numFolders);
977231200Smm	if (r < 0)
978231200Smm		return (r);
979231200Smm
980231200Smm	/* Make Size. */
981231200Smm	r = enc_uint64(a, kSize);
982231200Smm	if (r < 0)
983231200Smm		return (r);
984231200Smm
985231200Smm	if (numFolders > 1) {
986231200Smm		struct file *file = zip->file_list.first;
987231200Smm		for (;file != NULL; file = file->next) {
988231200Smm			if (file->size == 0)
989231200Smm				break;
990231200Smm			r = enc_uint64(a, file->size);
991231200Smm			if (r < 0)
992231200Smm				return (r);
993231200Smm		}
994231200Smm	} else {
995231200Smm		/* Write size. */
996231200Smm		r = enc_uint64(a, pack_size);
997231200Smm		if (r < 0)
998231200Smm			return (r);
999231200Smm	}
1000231200Smm
1001231200Smm	r = enc_uint64(a, kEnd);
1002231200Smm	if (r < 0)
1003231200Smm		return (r);
1004231200Smm
1005231200Smm	/*
1006231200Smm	 * Make UnPackInfo.
1007231200Smm	 */
1008231200Smm	r = enc_uint64(a, kUnPackInfo);
1009231200Smm	if (r < 0)
1010231200Smm		return (r);
1011231200Smm
1012231200Smm	/*
1013231200Smm	 * Make Folder.
1014231200Smm	 */
1015231200Smm	r = enc_uint64(a, kFolder);
1016231200Smm	if (r < 0)
1017231200Smm		return (r);
1018231200Smm
1019231200Smm	/* Write NumFolders. */
1020231200Smm	r = enc_uint64(a, numFolders);
1021231200Smm	if (r < 0)
1022231200Smm		return (r);
1023231200Smm
1024231200Smm	/* Write External. */
1025231200Smm	r = enc_uint64(a, 0);
1026231200Smm	if (r < 0)
1027231200Smm		return (r);
1028231200Smm
1029231200Smm	for (fi = 0; fi < numFolders; fi++) {
1030231200Smm		/* Write NumCoders. */
1031231200Smm		r = enc_uint64(a, num_coder);
1032231200Smm		if (r < 0)
1033231200Smm			return (r);
1034231200Smm
1035231200Smm		for (i = 0; i < num_coder; i++) {
1036231200Smm			unsigned codec_id = coders[i].codec;
1037231200Smm
1038231200Smm			/* Write Codec flag. */
1039231200Smm			archive_be64enc(codec_buff, codec_id);
1040231200Smm			for (codec_size = 8; codec_size > 0; codec_size--) {
1041231200Smm				if (codec_buff[8 - codec_size])
1042231200Smm					break;
1043231200Smm			}
1044231200Smm			if (codec_size == 0)
1045231200Smm				codec_size = 1;
1046231200Smm			if (coders[i].prop_size)
1047231200Smm				r = enc_uint64(a, codec_size | 0x20);
1048231200Smm			else
1049231200Smm				r = enc_uint64(a, codec_size);
1050231200Smm			if (r < 0)
1051231200Smm				return (r);
1052231200Smm
1053231200Smm			/* Write Codec ID. */
1054231200Smm			codec_size &= 0x0f;
1055248616Smm			r = (int)compress_out(a, &codec_buff[8-codec_size],
1056231200Smm				codec_size, ARCHIVE_Z_RUN);
1057231200Smm			if (r < 0)
1058231200Smm				return (r);
1059231200Smm
1060231200Smm			if (coders[i].prop_size) {
1061231200Smm				/* Write Codec property size. */
1062231200Smm				r = enc_uint64(a, coders[i].prop_size);
1063231200Smm				if (r < 0)
1064231200Smm					return (r);
1065231200Smm
1066231200Smm				/* Write Codec properties. */
1067248616Smm				r = (int)compress_out(a, coders[i].props,
1068231200Smm					coders[i].prop_size, ARCHIVE_Z_RUN);
1069231200Smm				if (r < 0)
1070231200Smm					return (r);
1071231200Smm			}
1072231200Smm		}
1073231200Smm	}
1074231200Smm
1075231200Smm	/*
1076231200Smm	 * Make CodersUnPackSize.
1077231200Smm	 */
1078231200Smm	r = enc_uint64(a, kCodersUnPackSize);
1079231200Smm	if (r < 0)
1080231200Smm		return (r);
1081231200Smm
1082231200Smm	if (numFolders > 1) {
1083231200Smm		struct file *file = zip->file_list.first;
1084231200Smm		for (;file != NULL; file = file->next) {
1085231200Smm			if (file->size == 0)
1086231200Smm				break;
1087231200Smm			r = enc_uint64(a, file->size);
1088231200Smm			if (r < 0)
1089231200Smm				return (r);
1090231200Smm		}
1091231200Smm
1092231200Smm	} else {
1093231200Smm		/* Write UnPackSize. */
1094231200Smm		r = enc_uint64(a, unpack_size);
1095231200Smm		if (r < 0)
1096231200Smm			return (r);
1097231200Smm	}
1098231200Smm
1099231200Smm	if (!substrm) {
1100231200Smm		uint8_t crc[4];
1101231200Smm		/*
1102231200Smm		 * Make CRC.
1103231200Smm		 */
1104231200Smm		r = enc_uint64(a, kCRC);
1105231200Smm		if (r < 0)
1106231200Smm			return (r);
1107231200Smm
1108231200Smm		/* All are defined */
1109231200Smm		r = enc_uint64(a, 1);
1110231200Smm		if (r < 0)
1111231200Smm			return (r);
1112231200Smm		archive_le32enc(crc, header_crc);
1113248616Smm		r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
1114231200Smm		if (r < 0)
1115231200Smm			return (r);
1116231200Smm	}
1117231200Smm
1118231200Smm	/* Write End. */
1119231200Smm	r = enc_uint64(a, kEnd);
1120231200Smm	if (r < 0)
1121231200Smm		return (r);
1122231200Smm
1123231200Smm	if (substrm) {
1124231200Smm		/*
1125231200Smm		 * Make SubStreamsInfo.
1126231200Smm		 */
1127231200Smm		r = make_substreamsInfo(a, coders);
1128231200Smm		if (r < 0)
1129231200Smm			return (r);
1130231200Smm	}
1131231200Smm
1132231200Smm
1133231200Smm	/* Write End. */
1134231200Smm	r = enc_uint64(a, kEnd);
1135231200Smm	if (r < 0)
1136231200Smm		return (r);
1137231200Smm
1138231200Smm	return (ARCHIVE_OK);
1139231200Smm}
1140231200Smm
1141231200Smm
1142231200Smm#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
1143231200Smmstatic uint64_t
1144232153SmmutcToFiletime(time_t t, long ns)
1145231200Smm{
1146231200Smm	uint64_t fileTime;
1147231200Smm
1148232153Smm	fileTime = t;
1149231200Smm	fileTime *= 10000000;
1150231200Smm	fileTime += ns / 100;
1151231200Smm	fileTime += EPOC_TIME;
1152231200Smm	return (fileTime);
1153231200Smm}
1154231200Smm
1155231200Smmstatic int
1156231200Smmmake_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)
1157231200Smm{
1158231200Smm	uint8_t filetime[8];
1159231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
1160231200Smm	struct file *file;
1161231200Smm	int r;
1162238856Smm	uint8_t b, mask;
1163231200Smm
1164231200Smm	/*
1165231200Smm	 * Make Time Bools.
1166231200Smm	 */
1167231200Smm	if (zip->total_number_time_defined[ti] == zip->total_number_entry) {
1168231200Smm		/* Write Time Type. */
1169231200Smm		r = enc_uint64(a, type);
1170231200Smm		if (r < 0)
1171231200Smm			return (r);
1172231200Smm		/* Write EmptyStream Size. */
1173231200Smm		r = enc_uint64(a, 2 + zip->total_number_entry * 8);
1174231200Smm		if (r < 0)
1175231200Smm			return (r);
1176231200Smm		/* All are defined. */
1177231200Smm		r = enc_uint64(a, 1);
1178231200Smm		if (r < 0)
1179231200Smm			return (r);
1180231200Smm	} else {
1181231200Smm		if (zip->total_number_time_defined[ti] == 0)
1182231200Smm			return (ARCHIVE_OK);
1183231200Smm
1184231200Smm		/* Write Time Type. */
1185231200Smm		r = enc_uint64(a, type);
1186231200Smm		if (r < 0)
1187231200Smm			return (r);
1188231200Smm		/* Write EmptyStream Size. */
1189231200Smm		r = enc_uint64(a, 2 + ((zip->total_number_entry + 7) >> 3)
1190231200Smm			+ zip->total_number_time_defined[ti] * 8);
1191231200Smm		if (r < 0)
1192231200Smm			return (r);
1193231200Smm
1194231200Smm		/* All are not defined. */
1195231200Smm		r = enc_uint64(a, 0);
1196231200Smm		if (r < 0)
1197231200Smm			return (r);
1198231200Smm
1199238856Smm		b = 0;
1200231200Smm		mask = 0x80;
1201231200Smm		file = zip->file_list.first;
1202231200Smm		for (;file != NULL; file = file->next) {
1203231200Smm			if (file->flg & flg)
1204238856Smm				b |= mask;
1205231200Smm			mask >>= 1;
1206231200Smm			if (mask == 0) {
1207248616Smm				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1208231200Smm				if (r < 0)
1209231200Smm					return (r);
1210231200Smm				mask = 0x80;
1211238856Smm				b = 0;
1212231200Smm			}
1213231200Smm		}
1214231200Smm		if (mask != 0x80) {
1215248616Smm			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1216231200Smm			if (r < 0)
1217231200Smm				return (r);
1218231200Smm		}
1219231200Smm	}
1220231200Smm
1221231200Smm	/* External. */
1222231200Smm	r = enc_uint64(a, 0);
1223231200Smm	if (r < 0)
1224231200Smm		return (r);
1225231200Smm
1226231200Smm
1227231200Smm	/*
1228231200Smm	 * Make Times.
1229231200Smm	 */
1230231200Smm	file = zip->file_list.first;
1231231200Smm	for (;file != NULL; file = file->next) {
1232231200Smm		if ((file->flg & flg) == 0)
1233231200Smm			continue;
1234231200Smm		archive_le64enc(filetime, utcToFiletime(file->times[ti].time,
1235231200Smm			file->times[ti].time_ns));
1236248616Smm		r = (int)compress_out(a, filetime, 8, ARCHIVE_Z_RUN);
1237231200Smm		if (r < 0)
1238231200Smm			return (r);
1239231200Smm	}
1240231200Smm
1241231200Smm	return (ARCHIVE_OK);
1242231200Smm}
1243231200Smm
1244231200Smmstatic int
1245231200Smmmake_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
1246231200Smm    uint64_t unpack_size, int codernum, struct coder *coders)
1247231200Smm{
1248231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
1249231200Smm	struct file *file;
1250231200Smm	int r;
1251238856Smm	uint8_t b, mask;
1252231200Smm
1253231200Smm	/*
1254231200Smm	 * Make FilesInfo.
1255231200Smm	 */
1256231200Smm	r = enc_uint64(a, kHeader);
1257231200Smm	if (r < 0)
1258231200Smm		return (r);
1259231200Smm
1260231200Smm	/*
1261231200Smm	 * If there are empty files only, do not write MainStreamInfo.
1262231200Smm	 */
1263231200Smm	if (zip->total_number_nonempty_entry) {
1264231200Smm		/*
1265231200Smm		 * Make MainStreamInfo.
1266231200Smm		 */
1267231200Smm		r = enc_uint64(a, kMainStreamsInfo);
1268231200Smm		if (r < 0)
1269231200Smm			return (r);
1270231200Smm		r = make_streamsInfo(a, offset, pack_size, unpack_size,
1271231200Smm		      codernum, coders, 1, 0);
1272231200Smm		if (r < 0)
1273231200Smm			return (r);
1274231200Smm	}
1275231200Smm
1276231200Smm	/*
1277231200Smm	 * Make FilesInfo.
1278231200Smm	 */
1279231200Smm	r = enc_uint64(a, kFilesInfo);
1280231200Smm	if (r < 0)
1281231200Smm		return (r);
1282231200Smm
1283231200Smm	/* Write numFiles. */
1284231200Smm	r = enc_uint64(a, zip->total_number_entry);
1285231200Smm	if (r < 0)
1286231200Smm		return (r);
1287231200Smm
1288231200Smm	if (zip->total_number_empty_entry > 0) {
1289231200Smm		/* Make EmptyStream. */
1290231200Smm		r = enc_uint64(a, kEmptyStream);
1291231200Smm		if (r < 0)
1292231200Smm			return (r);
1293231200Smm
1294231200Smm		/* Write EmptyStream Size. */
1295231200Smm		r = enc_uint64(a, (zip->total_number_entry+7)>>3);
1296231200Smm		if (r < 0)
1297231200Smm			return (r);
1298231200Smm
1299238856Smm		b = 0;
1300231200Smm		mask = 0x80;
1301231200Smm		file = zip->file_list.first;
1302231200Smm		for (;file != NULL; file = file->next) {
1303231200Smm			if (file->size == 0)
1304238856Smm				b |= mask;
1305231200Smm			mask >>= 1;
1306231200Smm			if (mask == 0) {
1307248616Smm				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1308231200Smm				if (r < 0)
1309231200Smm					return (r);
1310231200Smm				mask = 0x80;
1311238856Smm				b = 0;
1312231200Smm			}
1313231200Smm		}
1314231200Smm		if (mask != 0x80) {
1315248616Smm			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1316231200Smm			if (r < 0)
1317231200Smm				return (r);
1318231200Smm		}
1319231200Smm	}
1320231200Smm
1321231200Smm	if (zip->total_number_empty_entry > zip->total_number_dir_entry) {
1322231200Smm		/* Make EmptyFile. */
1323231200Smm		r = enc_uint64(a, kEmptyFile);
1324231200Smm		if (r < 0)
1325231200Smm			return (r);
1326231200Smm
1327231200Smm		/* Write EmptyFile Size. */
1328231200Smm		r = enc_uint64(a, (zip->total_number_empty_entry + 7) >> 3);
1329231200Smm		if (r < 0)
1330231200Smm			return (r);
1331231200Smm
1332238856Smm		b = 0;
1333231200Smm		mask = 0x80;
1334231200Smm		file = zip->file_list.first;
1335231200Smm		for (;file != NULL; file = file->next) {
1336231200Smm			if (file->size)
1337231200Smm				continue;
1338231200Smm			if (!file->dir)
1339238856Smm				b |= mask;
1340231200Smm			mask >>= 1;
1341231200Smm			if (mask == 0) {
1342248616Smm				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1343231200Smm				if (r < 0)
1344231200Smm					return (r);
1345231200Smm				mask = 0x80;
1346238856Smm				b = 0;
1347231200Smm			}
1348231200Smm		}
1349231200Smm		if (mask != 0x80) {
1350248616Smm			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
1351231200Smm			if (r < 0)
1352231200Smm				return (r);
1353231200Smm		}
1354231200Smm	}
1355231200Smm
1356231200Smm	/* Make Name. */
1357231200Smm	r = enc_uint64(a, kName);
1358231200Smm	if (r < 0)
1359231200Smm		return (r);
1360231200Smm
1361313570Smm	/* Write Name size. */
1362231200Smm	r = enc_uint64(a, zip->total_bytes_entry_name+1);
1363231200Smm	if (r < 0)
1364231200Smm		return (r);
1365231200Smm
1366231200Smm	/* Write dmy byte. */
1367231200Smm	r = enc_uint64(a, 0);
1368231200Smm	if (r < 0)
1369231200Smm		return (r);
1370231200Smm
1371231200Smm	file = zip->file_list.first;
1372231200Smm	for (;file != NULL; file = file->next) {
1373248616Smm		r = (int)compress_out(a, file->utf16name, file->name_len+2,
1374231200Smm			ARCHIVE_Z_RUN);
1375231200Smm		if (r < 0)
1376231200Smm			return (r);
1377231200Smm	}
1378231200Smm
1379231200Smm	/* Make MTime. */
1380231200Smm	r = make_time(a, kMTime, MTIME_IS_SET, MTIME);
1381231200Smm	if (r < 0)
1382231200Smm		return (r);
1383231200Smm
1384231200Smm	/* Make CTime. */
1385231200Smm	r = make_time(a, kCTime, CTIME_IS_SET, CTIME);
1386231200Smm	if (r < 0)
1387231200Smm		return (r);
1388231200Smm
1389231200Smm	/* Make ATime. */
1390231200Smm	r = make_time(a, kATime, ATIME_IS_SET, ATIME);
1391231200Smm	if (r < 0)
1392231200Smm		return (r);
1393231200Smm
1394231200Smm	/* Make Attributes. */
1395231200Smm	r = enc_uint64(a, kAttributes);
1396231200Smm	if (r < 0)
1397231200Smm		return (r);
1398231200Smm
1399231200Smm	/* Write Attributes size. */
1400231200Smm	r = enc_uint64(a, 2 + zip->total_number_entry * 4);
1401231200Smm	if (r < 0)
1402231200Smm		return (r);
1403231200Smm
1404231200Smm	/* Write "All Are Defined". */
1405231200Smm	r = enc_uint64(a, 1);
1406231200Smm	if (r < 0)
1407231200Smm		return (r);
1408231200Smm
1409231200Smm	/* Write dmy byte. */
1410231200Smm	r = enc_uint64(a, 0);
1411231200Smm	if (r < 0)
1412231200Smm		return (r);
1413231200Smm
1414231200Smm	file = zip->file_list.first;
1415231200Smm	for (;file != NULL; file = file->next) {
1416231200Smm		/*
1417231200Smm		 * High 16bits is unix mode.
1418231200Smm		 * Low 16bits is Windows attributes.
1419231200Smm		 */
1420231200Smm		uint32_t encattr, attr;
1421231200Smm		if (file->dir)
1422231200Smm			attr = 0x8010;
1423231200Smm		else
1424231200Smm			attr = 0x8020;
1425231200Smm		if ((file->mode & 0222) == 0)
1426231200Smm			attr |= 1;/* Read Only. */
1427231200Smm		attr |= ((uint32_t)file->mode) << 16;
1428231200Smm		archive_le32enc(&encattr, attr);
1429248616Smm		r = (int)compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);
1430231200Smm		if (r < 0)
1431231200Smm			return (r);
1432231200Smm	}
1433231200Smm
1434231200Smm	/* Write End. */
1435231200Smm	r = enc_uint64(a, kEnd);
1436231200Smm	if (r < 0)
1437231200Smm		return (r);
1438231200Smm
1439231200Smm	/* Write End. */
1440231200Smm	r = enc_uint64(a, kEnd);
1441231200Smm	if (r < 0)
1442231200Smm		return (r);
1443231200Smm
1444231200Smm	return (ARCHIVE_OK);
1445231200Smm}
1446231200Smm
1447231200Smm
1448231200Smmstatic int
1449231200Smm_7z_free(struct archive_write *a)
1450231200Smm{
1451231200Smm	struct _7zip *zip = (struct _7zip *)a->format_data;
1452231200Smm
1453299529Smm	/* Close the temporary file. */
1454299529Smm	if (zip->temp_fd >= 0)
1455299529Smm		close(zip->temp_fd);
1456299529Smm
1457231200Smm	file_free_register(zip);
1458231200Smm	compression_end(&(a->archive), &(zip->stream));
1459231200Smm	free(zip->coder.props);
1460231200Smm	free(zip);
1461231200Smm
1462231200Smm	return (ARCHIVE_OK);
1463231200Smm}
1464231200Smm
1465231200Smmstatic int
1466231200Smmfile_cmp_node(const struct archive_rb_node *n1,
1467231200Smm    const struct archive_rb_node *n2)
1468231200Smm{
1469232153Smm	const struct file *f1 = (const struct file *)n1;
1470232153Smm	const struct file *f2 = (const struct file *)n2;
1471231200Smm
1472231200Smm	if (f1->name_len == f2->name_len)
1473231200Smm		return (memcmp(f1->utf16name, f2->utf16name, f1->name_len));
1474231200Smm	return (f1->name_len > f2->name_len)?1:-1;
1475231200Smm}
1476231200Smm
1477231200Smmstatic int
1478231200Smmfile_cmp_key(const struct archive_rb_node *n, const void *key)
1479231200Smm{
1480232153Smm	const struct file *f = (const struct file *)n;
1481231200Smm
1482231200Smm	return (f->name_len - *(const char *)key);
1483231200Smm}
1484231200Smm
1485231200Smmstatic int
1486231200Smmfile_new(struct archive_write *a, struct archive_entry *entry,
1487231200Smm    struct file **newfile)
1488231200Smm{
1489231200Smm	struct _7zip *zip;
1490231200Smm	struct file *file;
1491231200Smm	const char *u16;
1492231200Smm	size_t u16len;
1493231200Smm	int ret = ARCHIVE_OK;
1494231200Smm
1495231200Smm	zip = (struct _7zip *)a->format_data;
1496231200Smm	*newfile = NULL;
1497231200Smm
1498231200Smm	file = calloc(1, sizeof(*file));
1499231200Smm	if (file == NULL) {
1500231200Smm		archive_set_error(&a->archive, ENOMEM,
1501231200Smm		    "Can't allocate memory");
1502231200Smm		return (ARCHIVE_FATAL);
1503231200Smm	}
1504231200Smm
1505231200Smm	if (0 > archive_entry_pathname_l(entry, &u16, &u16len, zip->sconv)) {
1506231200Smm		if (errno == ENOMEM) {
1507238856Smm			free(file);
1508231200Smm			archive_set_error(&a->archive, ENOMEM,
1509231200Smm			    "Can't allocate memory for UTF-16LE");
1510231200Smm			return (ARCHIVE_FATAL);
1511231200Smm		}
1512231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1513231200Smm		    "A filename cannot be converted to UTF-16LE;"
1514231200Smm		    "You should disable making Joliet extension");
1515231200Smm		ret = ARCHIVE_WARN;
1516231200Smm	}
1517231200Smm	file->utf16name = malloc(u16len + 2);
1518231200Smm	if (file->utf16name == NULL) {
1519238856Smm		free(file);
1520231200Smm		archive_set_error(&a->archive, ENOMEM,
1521231200Smm		    "Can't allocate memory for Name");
1522231200Smm		return (ARCHIVE_FATAL);
1523231200Smm	}
1524231200Smm	memcpy(file->utf16name, u16, u16len);
1525231200Smm	file->utf16name[u16len+0] = 0;
1526231200Smm	file->utf16name[u16len+1] = 0;
1527248616Smm	file->name_len = (unsigned)u16len;
1528231200Smm	file->mode = archive_entry_mode(entry);
1529231200Smm	if (archive_entry_filetype(entry) == AE_IFREG)
1530231200Smm		file->size = archive_entry_size(entry);
1531231200Smm	else
1532231200Smm		archive_entry_set_size(entry, 0);
1533231200Smm	if (archive_entry_filetype(entry) == AE_IFDIR)
1534231200Smm		file->dir = 1;
1535231200Smm	else if (archive_entry_filetype(entry) == AE_IFLNK)
1536231200Smm		file->size = strlen(archive_entry_symlink(entry));
1537231200Smm	if (archive_entry_mtime_is_set(entry)) {
1538231200Smm		file->flg |= MTIME_IS_SET;
1539231200Smm		file->times[MTIME].time = archive_entry_mtime(entry);
1540231200Smm		file->times[MTIME].time_ns = archive_entry_mtime_nsec(entry);
1541231200Smm	}
1542231200Smm	if (archive_entry_atime_is_set(entry)) {
1543231200Smm		file->flg |= ATIME_IS_SET;
1544231200Smm		file->times[ATIME].time = archive_entry_atime(entry);
1545231200Smm		file->times[ATIME].time_ns = archive_entry_atime_nsec(entry);
1546231200Smm	}
1547231200Smm	if (archive_entry_ctime_is_set(entry)) {
1548231200Smm		file->flg |= CTIME_IS_SET;
1549231200Smm		file->times[CTIME].time = archive_entry_ctime(entry);
1550231200Smm		file->times[CTIME].time_ns = archive_entry_ctime_nsec(entry);
1551231200Smm	}
1552231200Smm
1553231200Smm	*newfile = file;
1554231200Smm	return (ret);
1555231200Smm}
1556231200Smm
1557231200Smmstatic void
1558231200Smmfile_free(struct file *file)
1559231200Smm{
1560231200Smm	free(file->utf16name);
1561231200Smm	free(file);
1562231200Smm}
1563231200Smm
1564231200Smmstatic void
1565231200Smmfile_register(struct _7zip *zip, struct file *file)
1566231200Smm{
1567231200Smm	file->next = NULL;
1568231200Smm	*zip->file_list.last = file;
1569231200Smm	zip->file_list.last = &(file->next);
1570231200Smm}
1571231200Smm
1572231200Smmstatic void
1573231200Smmfile_init_register(struct _7zip *zip)
1574231200Smm{
1575231200Smm	zip->file_list.first = NULL;
1576231200Smm	zip->file_list.last = &(zip->file_list.first);
1577231200Smm}
1578231200Smm
1579231200Smmstatic void
1580231200Smmfile_free_register(struct _7zip *zip)
1581231200Smm{
1582231200Smm	struct file *file, *file_next;
1583231200Smm
1584231200Smm	file = zip->file_list.first;
1585231200Smm	while (file != NULL) {
1586231200Smm		file_next = file->next;
1587231200Smm		file_free(file);
1588231200Smm		file = file_next;
1589231200Smm	}
1590231200Smm}
1591231200Smm
1592231200Smmstatic void
1593231200Smmfile_register_empty(struct _7zip *zip, struct file *file)
1594231200Smm{
1595231200Smm	file->next = NULL;
1596231200Smm	*zip->empty_list.last = file;
1597231200Smm	zip->empty_list.last = &(file->next);
1598231200Smm}
1599231200Smm
1600231200Smmstatic void
1601231200Smmfile_init_register_empty(struct _7zip *zip)
1602231200Smm{
1603231200Smm	zip->empty_list.first = NULL;
1604231200Smm	zip->empty_list.last = &(zip->empty_list.first);
1605231200Smm}
1606231200Smm
1607232153Smm#if !defined(HAVE_ZLIB_H) || !defined(HAVE_BZLIB_H) ||\
1608232153Smm	 !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
1609231200Smmstatic int
1610231200Smmcompression_unsupported_encoder(struct archive *a,
1611231200Smm    struct la_zstream *lastrm, const char *name)
1612231200Smm{
1613231200Smm
1614231200Smm	archive_set_error(a, ARCHIVE_ERRNO_MISC,
1615231200Smm	    "%s compression not supported on this platform", name);
1616231200Smm	lastrm->valid = 0;
1617231200Smm	lastrm->real_stream = NULL;
1618231200Smm	return (ARCHIVE_FAILED);
1619231200Smm}
1620231200Smm#endif
1621231200Smm
1622231200Smm/*
1623231200Smm * _7_COPY compressor.
1624231200Smm */
1625231200Smmstatic int
1626231200Smmcompression_init_encoder_copy(struct archive *a, struct la_zstream *lastrm)
1627231200Smm{
1628231200Smm
1629231200Smm	if (lastrm->valid)
1630231200Smm		compression_end(a, lastrm);
1631231200Smm	lastrm->valid = 1;
1632231200Smm	lastrm->code = compression_code_copy;
1633231200Smm	lastrm->end = compression_end_copy;
1634231200Smm	return (ARCHIVE_OK);
1635231200Smm}
1636231200Smm
1637231200Smmstatic int
1638231200Smmcompression_code_copy(struct archive *a,
1639231200Smm    struct la_zstream *lastrm, enum la_zaction action)
1640231200Smm{
1641231200Smm	size_t bytes;
1642231200Smm
1643231200Smm	(void)a; /* UNUSED */
1644231200Smm	if (lastrm->avail_out > lastrm->avail_in)
1645231200Smm		bytes = lastrm->avail_in;
1646231200Smm	else
1647231200Smm		bytes = lastrm->avail_out;
1648231200Smm	if (bytes) {
1649231200Smm		memcpy(lastrm->next_out, lastrm->next_in, bytes);
1650231200Smm		lastrm->next_in += bytes;
1651231200Smm		lastrm->avail_in -= bytes;
1652231200Smm		lastrm->total_in += bytes;
1653231200Smm		lastrm->next_out += bytes;
1654231200Smm		lastrm->avail_out -= bytes;
1655231200Smm		lastrm->total_out += bytes;
1656231200Smm	}
1657231200Smm	if (action == ARCHIVE_Z_FINISH && lastrm->avail_in == 0)
1658231200Smm		return (ARCHIVE_EOF);
1659231200Smm	return (ARCHIVE_OK);
1660231200Smm}
1661231200Smm
1662231200Smmstatic int
1663231200Smmcompression_end_copy(struct archive *a, struct la_zstream *lastrm)
1664231200Smm{
1665231200Smm	(void)a; /* UNUSED */
1666231200Smm	lastrm->valid = 0;
1667231200Smm	return (ARCHIVE_OK);
1668231200Smm}
1669231200Smm
1670231200Smm/*
1671231200Smm * _7_DEFLATE compressor.
1672231200Smm */
1673231200Smm#ifdef HAVE_ZLIB_H
1674231200Smmstatic int
1675231200Smmcompression_init_encoder_deflate(struct archive *a,
1676231200Smm    struct la_zstream *lastrm, int level, int withheader)
1677231200Smm{
1678231200Smm	z_stream *strm;
1679231200Smm
1680231200Smm	if (lastrm->valid)
1681231200Smm		compression_end(a, lastrm);
1682231200Smm	strm = calloc(1, sizeof(*strm));
1683231200Smm	if (strm == NULL) {
1684231200Smm		archive_set_error(a, ENOMEM,
1685231200Smm		    "Can't allocate memory for gzip stream");
1686231200Smm		return (ARCHIVE_FATAL);
1687231200Smm	}
1688231200Smm	/* zlib.h is not const-correct, so we need this one bit
1689231200Smm	 * of ugly hackery to convert a const * pointer to
1690231200Smm	 * a non-const pointer. */
1691231200Smm	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
1692248616Smm	strm->avail_in = (uInt)lastrm->avail_in;
1693238856Smm	strm->total_in = (uLong)lastrm->total_in;
1694231200Smm	strm->next_out = lastrm->next_out;
1695248616Smm	strm->avail_out = (uInt)lastrm->avail_out;
1696238856Smm	strm->total_out = (uLong)lastrm->total_out;
1697231200Smm	if (deflateInit2(strm, level, Z_DEFLATED,
1698231200Smm	    (withheader)?15:-15,
1699231200Smm	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
1700231200Smm		free(strm);
1701231200Smm		lastrm->real_stream = NULL;
1702231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1703231200Smm		    "Internal error initializing compression library");
1704231200Smm		return (ARCHIVE_FATAL);
1705231200Smm	}
1706231200Smm	lastrm->real_stream = strm;
1707231200Smm	lastrm->valid = 1;
1708231200Smm	lastrm->code = compression_code_deflate;
1709231200Smm	lastrm->end = compression_end_deflate;
1710231200Smm	return (ARCHIVE_OK);
1711231200Smm}
1712231200Smm
1713231200Smmstatic int
1714231200Smmcompression_code_deflate(struct archive *a,
1715231200Smm    struct la_zstream *lastrm, enum la_zaction action)
1716231200Smm{
1717231200Smm	z_stream *strm;
1718231200Smm	int r;
1719231200Smm
1720231200Smm	strm = (z_stream *)lastrm->real_stream;
1721231200Smm	/* zlib.h is not const-correct, so we need this one bit
1722231200Smm	 * of ugly hackery to convert a const * pointer to
1723231200Smm	 * a non-const pointer. */
1724231200Smm	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
1725248616Smm	strm->avail_in = (uInt)lastrm->avail_in;
1726238856Smm	strm->total_in = (uLong)lastrm->total_in;
1727231200Smm	strm->next_out = lastrm->next_out;
1728248616Smm	strm->avail_out = (uInt)lastrm->avail_out;
1729238856Smm	strm->total_out = (uLong)lastrm->total_out;
1730231200Smm	r = deflate(strm,
1731231200Smm	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
1732231200Smm	lastrm->next_in = strm->next_in;
1733231200Smm	lastrm->avail_in = strm->avail_in;
1734231200Smm	lastrm->total_in = strm->total_in;
1735231200Smm	lastrm->next_out = strm->next_out;
1736231200Smm	lastrm->avail_out = strm->avail_out;
1737231200Smm	lastrm->total_out = strm->total_out;
1738231200Smm	switch (r) {
1739231200Smm	case Z_OK:
1740231200Smm		return (ARCHIVE_OK);
1741231200Smm	case Z_STREAM_END:
1742231200Smm		return (ARCHIVE_EOF);
1743231200Smm	default:
1744231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1745231200Smm		    "GZip compression failed:"
1746231200Smm		    " deflate() call returned status %d", r);
1747231200Smm		return (ARCHIVE_FATAL);
1748231200Smm	}
1749231200Smm}
1750231200Smm
1751231200Smmstatic int
1752231200Smmcompression_end_deflate(struct archive *a, struct la_zstream *lastrm)
1753231200Smm{
1754231200Smm	z_stream *strm;
1755231200Smm	int r;
1756231200Smm
1757231200Smm	strm = (z_stream *)lastrm->real_stream;
1758231200Smm	r = deflateEnd(strm);
1759231200Smm	free(strm);
1760231200Smm	lastrm->real_stream = NULL;
1761231200Smm	lastrm->valid = 0;
1762231200Smm	if (r != Z_OK) {
1763231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1764231200Smm		    "Failed to clean up compressor");
1765231200Smm		return (ARCHIVE_FATAL);
1766231200Smm	}
1767231200Smm	return (ARCHIVE_OK);
1768231200Smm}
1769231200Smm#else
1770231200Smmstatic int
1771231200Smmcompression_init_encoder_deflate(struct archive *a,
1772231200Smm    struct la_zstream *lastrm, int level, int withheader)
1773231200Smm{
1774231200Smm
1775231200Smm	(void) level; /* UNUSED */
1776231200Smm	(void) withheader; /* UNUSED */
1777231200Smm	if (lastrm->valid)
1778231200Smm		compression_end(a, lastrm);
1779231200Smm	return (compression_unsupported_encoder(a, lastrm, "deflate"));
1780231200Smm}
1781231200Smm#endif
1782231200Smm
1783231200Smm/*
1784231200Smm * _7_BZIP2 compressor.
1785231200Smm */
1786231200Smm#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
1787231200Smmstatic int
1788231200Smmcompression_init_encoder_bzip2(struct archive *a,
1789231200Smm    struct la_zstream *lastrm, int level)
1790231200Smm{
1791231200Smm	bz_stream *strm;
1792231200Smm
1793231200Smm	if (lastrm->valid)
1794231200Smm		compression_end(a, lastrm);
1795231200Smm	strm = calloc(1, sizeof(*strm));
1796231200Smm	if (strm == NULL) {
1797231200Smm		archive_set_error(a, ENOMEM,
1798231200Smm		    "Can't allocate memory for bzip2 stream");
1799231200Smm		return (ARCHIVE_FATAL);
1800231200Smm	}
1801231200Smm	/* bzlib.h is not const-correct, so we need this one bit
1802231200Smm	 * of ugly hackery to convert a const * pointer to
1803231200Smm	 * a non-const pointer. */
1804231200Smm	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
1805231200Smm	strm->avail_in = lastrm->avail_in;
1806231200Smm	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
1807231200Smm	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
1808231200Smm	strm->next_out = (char *)lastrm->next_out;
1809231200Smm	strm->avail_out = lastrm->avail_out;
1810231200Smm	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
1811231200Smm	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
1812231200Smm	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
1813231200Smm		free(strm);
1814231200Smm		lastrm->real_stream = NULL;
1815231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1816231200Smm		    "Internal error initializing compression library");
1817231200Smm		return (ARCHIVE_FATAL);
1818231200Smm	}
1819231200Smm	lastrm->real_stream = strm;
1820231200Smm	lastrm->valid = 1;
1821231200Smm	lastrm->code = compression_code_bzip2;
1822231200Smm	lastrm->end = compression_end_bzip2;
1823231200Smm	return (ARCHIVE_OK);
1824231200Smm}
1825231200Smm
1826231200Smmstatic int
1827231200Smmcompression_code_bzip2(struct archive *a,
1828231200Smm    struct la_zstream *lastrm, enum la_zaction action)
1829231200Smm{
1830231200Smm	bz_stream *strm;
1831231200Smm	int r;
1832231200Smm
1833231200Smm	strm = (bz_stream *)lastrm->real_stream;
1834231200Smm	/* bzlib.h is not const-correct, so we need this one bit
1835231200Smm	 * of ugly hackery to convert a const * pointer to
1836231200Smm	 * a non-const pointer. */
1837231200Smm	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
1838231200Smm	strm->avail_in = lastrm->avail_in;
1839231200Smm	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
1840231200Smm	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
1841231200Smm	strm->next_out = (char *)lastrm->next_out;
1842231200Smm	strm->avail_out = lastrm->avail_out;
1843231200Smm	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
1844231200Smm	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
1845231200Smm	r = BZ2_bzCompress(strm,
1846231200Smm	    (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
1847231200Smm	lastrm->next_in = (const unsigned char *)strm->next_in;
1848231200Smm	lastrm->avail_in = strm->avail_in;
1849231200Smm	lastrm->total_in =
1850231200Smm	    (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
1851231200Smm	    + (uint64_t)(uint32_t)strm->total_in_lo32;
1852231200Smm	lastrm->next_out = (unsigned char *)strm->next_out;
1853231200Smm	lastrm->avail_out = strm->avail_out;
1854231200Smm	lastrm->total_out =
1855231200Smm	    (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
1856231200Smm	    + (uint64_t)(uint32_t)strm->total_out_lo32;
1857231200Smm	switch (r) {
1858231200Smm	case BZ_RUN_OK:     /* Non-finishing */
1859231200Smm	case BZ_FINISH_OK:  /* Finishing: There's more work to do */
1860231200Smm		return (ARCHIVE_OK);
1861231200Smm	case BZ_STREAM_END: /* Finishing: all done */
1862231200Smm		/* Only occurs in finishing case */
1863231200Smm		return (ARCHIVE_EOF);
1864231200Smm	default:
1865231200Smm		/* Any other return value indicates an error */
1866231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1867231200Smm		    "Bzip2 compression failed:"
1868231200Smm		    " BZ2_bzCompress() call returned status %d", r);
1869231200Smm		return (ARCHIVE_FATAL);
1870231200Smm	}
1871231200Smm}
1872231200Smm
1873231200Smmstatic int
1874231200Smmcompression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
1875231200Smm{
1876231200Smm	bz_stream *strm;
1877231200Smm	int r;
1878231200Smm
1879231200Smm	strm = (bz_stream *)lastrm->real_stream;
1880231200Smm	r = BZ2_bzCompressEnd(strm);
1881231200Smm	free(strm);
1882231200Smm	lastrm->real_stream = NULL;
1883231200Smm	lastrm->valid = 0;
1884231200Smm	if (r != BZ_OK) {
1885231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1886231200Smm		    "Failed to clean up compressor");
1887231200Smm		return (ARCHIVE_FATAL);
1888231200Smm	}
1889231200Smm	return (ARCHIVE_OK);
1890231200Smm}
1891231200Smm
1892231200Smm#else
1893231200Smmstatic int
1894231200Smmcompression_init_encoder_bzip2(struct archive *a,
1895231200Smm    struct la_zstream *lastrm, int level)
1896231200Smm{
1897231200Smm
1898231200Smm	(void) level; /* UNUSED */
1899231200Smm	if (lastrm->valid)
1900231200Smm		compression_end(a, lastrm);
1901231200Smm	return (compression_unsupported_encoder(a, lastrm, "bzip2"));
1902231200Smm}
1903231200Smm#endif
1904231200Smm
1905231200Smm/*
1906231200Smm * _7_LZMA1, _7_LZMA2 compressor.
1907231200Smm */
1908231200Smm#if defined(HAVE_LZMA_H)
1909231200Smmstatic int
1910231200Smmcompression_init_encoder_lzma(struct archive *a,
1911231200Smm    struct la_zstream *lastrm, int level, uint64_t filter_id)
1912231200Smm{
1913231200Smm	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
1914231200Smm	lzma_stream *strm;
1915231200Smm	lzma_filter *lzmafilters;
1916231200Smm	lzma_options_lzma lzma_opt;
1917231200Smm	int r;
1918231200Smm
1919231200Smm	if (lastrm->valid)
1920231200Smm		compression_end(a, lastrm);
1921231200Smm	strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
1922231200Smm	if (strm == NULL) {
1923231200Smm		archive_set_error(a, ENOMEM,
1924231200Smm		    "Can't allocate memory for lzma stream");
1925231200Smm		return (ARCHIVE_FATAL);
1926231200Smm	}
1927231200Smm	lzmafilters = (lzma_filter *)(strm+1);
1928231200Smm	if (level > 6)
1929231200Smm		level = 6;
1930231200Smm	if (lzma_lzma_preset(&lzma_opt, level)) {
1931238856Smm		free(strm);
1932231200Smm		lastrm->real_stream = NULL;
1933231200Smm		archive_set_error(a, ENOMEM,
1934231200Smm		    "Internal error initializing compression library");
1935231200Smm		return (ARCHIVE_FATAL);
1936231200Smm	}
1937231200Smm	lzmafilters[0].id = filter_id;
1938231200Smm	lzmafilters[0].options = &lzma_opt;
1939231200Smm	lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
1940231200Smm
1941231200Smm	r = lzma_properties_size(&(lastrm->prop_size), lzmafilters);
1942231200Smm	if (r != LZMA_OK) {
1943231200Smm		free(strm);
1944231200Smm		lastrm->real_stream = NULL;
1945231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1946231200Smm		    "lzma_properties_size failed");
1947231200Smm		return (ARCHIVE_FATAL);
1948231200Smm	}
1949231200Smm	if (lastrm->prop_size) {
1950231200Smm		lastrm->props = malloc(lastrm->prop_size);
1951231200Smm		if (lastrm->props == NULL) {
1952231200Smm			free(strm);
1953231200Smm			lastrm->real_stream = NULL;
1954231200Smm			archive_set_error(a, ENOMEM,
1955231200Smm			    "Cannot allocate memory");
1956231200Smm			return (ARCHIVE_FATAL);
1957231200Smm		}
1958231200Smm		r = lzma_properties_encode(lzmafilters,  lastrm->props);
1959231200Smm		if (r != LZMA_OK) {
1960231200Smm			free(strm);
1961231200Smm			lastrm->real_stream = NULL;
1962231200Smm			archive_set_error(a, ARCHIVE_ERRNO_MISC,
1963231200Smm			    "lzma_properties_encode failed");
1964231200Smm			return (ARCHIVE_FATAL);
1965231200Smm		}
1966231200Smm	}
1967231200Smm
1968231200Smm	*strm = lzma_init_data;
1969231200Smm	r = lzma_raw_encoder(strm, lzmafilters);
1970231200Smm	switch (r) {
1971231200Smm	case LZMA_OK:
1972231200Smm		lastrm->real_stream = strm;
1973231200Smm		lastrm->valid = 1;
1974231200Smm		lastrm->code = compression_code_lzma;
1975231200Smm		lastrm->end = compression_end_lzma;
1976231200Smm		r = ARCHIVE_OK;
1977231200Smm		break;
1978231200Smm	case LZMA_MEM_ERROR:
1979231200Smm		free(strm);
1980231200Smm		lastrm->real_stream = NULL;
1981231200Smm		archive_set_error(a, ENOMEM,
1982231200Smm		    "Internal error initializing compression library: "
1983231200Smm		    "Cannot allocate memory");
1984231200Smm		r =  ARCHIVE_FATAL;
1985231200Smm		break;
1986231200Smm        default:
1987231200Smm		free(strm);
1988231200Smm		lastrm->real_stream = NULL;
1989231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1990231200Smm		    "Internal error initializing compression library: "
1991231200Smm		    "It's a bug in liblzma");
1992231200Smm		r =  ARCHIVE_FATAL;
1993231200Smm		break;
1994231200Smm	}
1995231200Smm	return (r);
1996231200Smm}
1997231200Smm
1998231200Smmstatic int
1999231200Smmcompression_init_encoder_lzma1(struct archive *a,
2000231200Smm    struct la_zstream *lastrm, int level)
2001231200Smm{
2002231200Smm	return compression_init_encoder_lzma(a, lastrm, level,
2003231200Smm		    LZMA_FILTER_LZMA1);
2004231200Smm}
2005231200Smm
2006231200Smmstatic int
2007231200Smmcompression_init_encoder_lzma2(struct archive *a,
2008231200Smm    struct la_zstream *lastrm, int level)
2009231200Smm{
2010231200Smm	return compression_init_encoder_lzma(a, lastrm, level,
2011231200Smm		    LZMA_FILTER_LZMA2);
2012231200Smm}
2013231200Smm
2014231200Smmstatic int
2015231200Smmcompression_code_lzma(struct archive *a,
2016231200Smm    struct la_zstream *lastrm, enum la_zaction action)
2017231200Smm{
2018231200Smm	lzma_stream *strm;
2019231200Smm	int r;
2020231200Smm
2021231200Smm	strm = (lzma_stream *)lastrm->real_stream;
2022231200Smm	strm->next_in = lastrm->next_in;
2023231200Smm	strm->avail_in = lastrm->avail_in;
2024231200Smm	strm->total_in = lastrm->total_in;
2025231200Smm	strm->next_out = lastrm->next_out;
2026231200Smm	strm->avail_out = lastrm->avail_out;
2027231200Smm	strm->total_out = lastrm->total_out;
2028231200Smm	r = lzma_code(strm,
2029231200Smm	    (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
2030231200Smm	lastrm->next_in = strm->next_in;
2031231200Smm	lastrm->avail_in = strm->avail_in;
2032231200Smm	lastrm->total_in = strm->total_in;
2033231200Smm	lastrm->next_out = strm->next_out;
2034231200Smm	lastrm->avail_out = strm->avail_out;
2035231200Smm	lastrm->total_out = strm->total_out;
2036231200Smm	switch (r) {
2037231200Smm	case LZMA_OK:
2038231200Smm		/* Non-finishing case */
2039231200Smm		return (ARCHIVE_OK);
2040231200Smm	case LZMA_STREAM_END:
2041231200Smm		/* This return can only occur in finishing case. */
2042231200Smm		return (ARCHIVE_EOF);
2043231200Smm	case LZMA_MEMLIMIT_ERROR:
2044231200Smm		archive_set_error(a, ENOMEM,
2045231200Smm		    "lzma compression error:"
2046231200Smm		    " %ju MiB would have been needed",
2047231200Smm		    (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
2048231200Smm			/ (1024 * 1024)));
2049231200Smm		return (ARCHIVE_FATAL);
2050231200Smm	default:
2051231200Smm		/* Any other return value indicates an error */
2052231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2053231200Smm		    "lzma compression failed:"
2054231200Smm		    " lzma_code() call returned status %d", r);
2055231200Smm		return (ARCHIVE_FATAL);
2056231200Smm	}
2057231200Smm}
2058231200Smm
2059231200Smmstatic int
2060231200Smmcompression_end_lzma(struct archive *a, struct la_zstream *lastrm)
2061231200Smm{
2062231200Smm	lzma_stream *strm;
2063231200Smm
2064231200Smm	(void)a; /* UNUSED */
2065231200Smm	strm = (lzma_stream *)lastrm->real_stream;
2066231200Smm	lzma_end(strm);
2067231200Smm	free(strm);
2068231200Smm	lastrm->valid = 0;
2069231200Smm	lastrm->real_stream = NULL;
2070231200Smm	return (ARCHIVE_OK);
2071231200Smm}
2072231200Smm#else
2073231200Smmstatic int
2074231200Smmcompression_init_encoder_lzma1(struct archive *a,
2075231200Smm    struct la_zstream *lastrm, int level)
2076231200Smm{
2077231200Smm
2078231200Smm	(void) level; /* UNUSED */
2079231200Smm	if (lastrm->valid)
2080231200Smm		compression_end(a, lastrm);
2081231200Smm	return (compression_unsupported_encoder(a, lastrm, "lzma"));
2082231200Smm}
2083231200Smmstatic int
2084231200Smmcompression_init_encoder_lzma2(struct archive *a,
2085231200Smm    struct la_zstream *lastrm, int level)
2086231200Smm{
2087231200Smm
2088231200Smm	(void) level; /* UNUSED */
2089231200Smm	if (lastrm->valid)
2090231200Smm		compression_end(a, lastrm);
2091231200Smm	return (compression_unsupported_encoder(a, lastrm, "lzma"));
2092231200Smm}
2093231200Smm#endif
2094231200Smm
2095231200Smm/*
2096231200Smm * _7_PPMD compressor.
2097231200Smm */
2098231200Smmstatic void
2099231200Smmppmd_write(void *p, Byte b)
2100231200Smm{
2101231200Smm	struct archive_write *a = ((IByteOut *)p)->a;
2102231200Smm	struct _7zip *zip = (struct _7zip *)(a->format_data);
2103231200Smm	struct la_zstream *lastrm = &(zip->stream);
2104231200Smm	struct ppmd_stream *strm;
2105231200Smm
2106231200Smm	if (lastrm->avail_out) {
2107231200Smm		*lastrm->next_out++ = b;
2108231200Smm		lastrm->avail_out--;
2109231200Smm		lastrm->total_out++;
2110231200Smm		return;
2111231200Smm	}
2112231200Smm	strm = (struct ppmd_stream *)lastrm->real_stream;
2113231200Smm	if (strm->buff_ptr < strm->buff_end) {
2114231200Smm		*strm->buff_ptr++ = b;
2115231200Smm		strm->buff_bytes++;
2116231200Smm	}
2117231200Smm}
2118231200Smm
2119231200Smmstatic int
2120231200Smmcompression_init_encoder_ppmd(struct archive *a,
2121231200Smm    struct la_zstream *lastrm, unsigned maxOrder, uint32_t msize)
2122231200Smm{
2123231200Smm	struct ppmd_stream *strm;
2124231200Smm	uint8_t *props;
2125231200Smm	int r;
2126231200Smm
2127231200Smm	if (lastrm->valid)
2128231200Smm		compression_end(a, lastrm);
2129231200Smm	strm = calloc(1, sizeof(*strm));
2130231200Smm	if (strm == NULL) {
2131231200Smm		archive_set_error(a, ENOMEM,
2132231200Smm		    "Can't allocate memory for PPMd");
2133231200Smm		return (ARCHIVE_FATAL);
2134231200Smm	}
2135231200Smm	strm->buff = malloc(32);
2136231200Smm	if (strm->buff == NULL) {
2137231200Smm		free(strm);
2138231200Smm		archive_set_error(a, ENOMEM,
2139231200Smm		    "Can't allocate memory for PPMd");
2140231200Smm		return (ARCHIVE_FATAL);
2141231200Smm	}
2142231200Smm	strm->buff_ptr = strm->buff;
2143231200Smm	strm->buff_end = strm->buff + 32;
2144231200Smm
2145231200Smm	props = malloc(1+4);
2146231200Smm	if (props == NULL) {
2147231200Smm		free(strm->buff);
2148231200Smm		free(strm);
2149231200Smm		archive_set_error(a, ENOMEM,
2150231200Smm		    "Coludn't allocate memory for PPMd");
2151231200Smm		return (ARCHIVE_FATAL);
2152231200Smm	}
2153231200Smm	props[0] = maxOrder;
2154231200Smm	archive_le32enc(props+1, msize);
2155231200Smm	__archive_ppmd7_functions.Ppmd7_Construct(&strm->ppmd7_context);
2156231200Smm	r = __archive_ppmd7_functions.Ppmd7_Alloc(
2157328827Smm		&strm->ppmd7_context, msize);
2158231200Smm	if (r == 0) {
2159231200Smm		free(strm->buff);
2160231200Smm		free(strm);
2161231200Smm		free(props);
2162231200Smm		archive_set_error(a, ENOMEM,
2163231200Smm		    "Coludn't allocate memory for PPMd");
2164231200Smm		return (ARCHIVE_FATAL);
2165231200Smm	}
2166231200Smm	__archive_ppmd7_functions.Ppmd7_Init(&(strm->ppmd7_context), maxOrder);
2167231200Smm	strm->byteout.a = (struct archive_write *)a;
2168231200Smm	strm->byteout.Write = ppmd_write;
2169231200Smm	strm->range_enc.Stream = &(strm->byteout);
2170231200Smm	__archive_ppmd7_functions.Ppmd7z_RangeEnc_Init(&(strm->range_enc));
2171231200Smm	strm->stat = 0;
2172231200Smm
2173231200Smm	lastrm->real_stream = strm;
2174231200Smm	lastrm->valid = 1;
2175231200Smm	lastrm->code = compression_code_ppmd;
2176231200Smm	lastrm->end = compression_end_ppmd;
2177231200Smm	lastrm->prop_size = 5;
2178231200Smm	lastrm->props = props;
2179231200Smm	return (ARCHIVE_OK);
2180231200Smm}
2181231200Smm
2182231200Smmstatic int
2183231200Smmcompression_code_ppmd(struct archive *a,
2184231200Smm    struct la_zstream *lastrm, enum la_zaction action)
2185231200Smm{
2186231200Smm	struct ppmd_stream *strm;
2187231200Smm
2188232153Smm	(void)a; /* UNUSED */
2189232153Smm
2190231200Smm	strm = (struct ppmd_stream *)lastrm->real_stream;
2191231200Smm
2192231200Smm	/* Copy encoded data if there are remaining bytes from previous call. */
2193231200Smm	if (strm->buff_bytes) {
2194231200Smm		uint8_t *p = strm->buff_ptr - strm->buff_bytes;
2195231200Smm		while (lastrm->avail_out && strm->buff_bytes) {
2196231200Smm			*lastrm->next_out++ = *p++;
2197231200Smm			lastrm->avail_out--;
2198231200Smm			lastrm->total_out++;
2199231200Smm			strm->buff_bytes--;
2200231200Smm		}
2201231200Smm		if (strm->buff_bytes)
2202231200Smm			return (ARCHIVE_OK);
2203231200Smm		if (strm->stat == 1)
2204231200Smm			return (ARCHIVE_EOF);
2205231200Smm		strm->buff_ptr = strm->buff;
2206231200Smm	}
2207231200Smm	while (lastrm->avail_in && lastrm->avail_out) {
2208231200Smm		__archive_ppmd7_functions.Ppmd7_EncodeSymbol(
2209231200Smm			&(strm->ppmd7_context), &(strm->range_enc),
2210231200Smm			*lastrm->next_in++);
2211231200Smm		lastrm->avail_in--;
2212231200Smm		lastrm->total_in++;
2213231200Smm	}
2214231200Smm	if (lastrm->avail_in == 0 && action == ARCHIVE_Z_FINISH) {
2215231200Smm		__archive_ppmd7_functions.Ppmd7z_RangeEnc_FlushData(
2216231200Smm			&(strm->range_enc));
2217231200Smm		strm->stat = 1;
2218231200Smm		/* Return EOF if there are no remaining bytes. */
2219231200Smm		if (strm->buff_bytes == 0)
2220231200Smm			return (ARCHIVE_EOF);
2221231200Smm	}
2222231200Smm	return (ARCHIVE_OK);
2223231200Smm}
2224231200Smm
2225231200Smmstatic int
2226231200Smmcompression_end_ppmd(struct archive *a, struct la_zstream *lastrm)
2227231200Smm{
2228231200Smm	struct ppmd_stream *strm;
2229231200Smm
2230232153Smm	(void)a; /* UNUSED */
2231232153Smm
2232231200Smm	strm = (struct ppmd_stream *)lastrm->real_stream;
2233328827Smm	__archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context);
2234231200Smm	free(strm->buff);
2235231200Smm	free(strm);
2236231200Smm	lastrm->real_stream = NULL;
2237231200Smm	lastrm->valid = 0;
2238231200Smm	return (ARCHIVE_OK);
2239231200Smm}
2240231200Smm
2241231200Smm/*
2242231200Smm * Universal compressor initializer.
2243231200Smm */
2244231200Smmstatic int
2245231200Smm_7z_compression_init_encoder(struct archive_write *a, unsigned compression,
2246231200Smm    int compression_level)
2247231200Smm{
2248231200Smm	struct _7zip *zip;
2249231200Smm	int r;
2250231200Smm
2251231200Smm	zip = (struct _7zip *)a->format_data;
2252231200Smm	switch (compression) {
2253231200Smm	case _7Z_DEFLATE:
2254231200Smm		r = compression_init_encoder_deflate(
2255231200Smm		    &(a->archive), &(zip->stream),
2256231200Smm		    compression_level, 0);
2257231200Smm		break;
2258231200Smm	case _7Z_BZIP2:
2259231200Smm		r = compression_init_encoder_bzip2(
2260231200Smm		    &(a->archive), &(zip->stream),
2261231200Smm		    compression_level);
2262231200Smm		break;
2263231200Smm	case _7Z_LZMA1:
2264231200Smm		r = compression_init_encoder_lzma1(
2265231200Smm		    &(a->archive), &(zip->stream),
2266231200Smm		    compression_level);
2267231200Smm		break;
2268231200Smm	case _7Z_LZMA2:
2269231200Smm		r = compression_init_encoder_lzma2(
2270231200Smm		    &(a->archive), &(zip->stream),
2271231200Smm		    compression_level);
2272231200Smm		break;
2273231200Smm	case _7Z_PPMD:
2274231200Smm		r = compression_init_encoder_ppmd(
2275231200Smm		    &(a->archive), &(zip->stream),
2276231200Smm		    PPMD7_DEFAULT_ORDER, PPMD7_DEFAULT_MEM_SIZE);
2277231200Smm		break;
2278231200Smm	case _7Z_COPY:
2279231200Smm	default:
2280231200Smm		r = compression_init_encoder_copy(
2281231200Smm		    &(a->archive), &(zip->stream));
2282231200Smm		break;
2283231200Smm	}
2284231200Smm	if (r == ARCHIVE_OK) {
2285231200Smm		zip->stream.total_in = 0;
2286231200Smm		zip->stream.next_out = zip->wbuff;
2287231200Smm		zip->stream.avail_out = sizeof(zip->wbuff);
2288231200Smm		zip->stream.total_out = 0;
2289231200Smm	}
2290231200Smm
2291231200Smm	return (r);
2292231200Smm}
2293231200Smm
2294231200Smmstatic int
2295231200Smmcompression_code(struct archive *a, struct la_zstream *lastrm,
2296231200Smm    enum la_zaction action)
2297231200Smm{
2298231200Smm	if (lastrm->valid)
2299231200Smm		return (lastrm->code(a, lastrm, action));
2300231200Smm	return (ARCHIVE_OK);
2301231200Smm}
2302231200Smm
2303231200Smmstatic int
2304231200Smmcompression_end(struct archive *a, struct la_zstream *lastrm)
2305231200Smm{
2306231200Smm	if (lastrm->valid) {
2307231200Smm		lastrm->prop_size = 0;
2308231200Smm		free(lastrm->props);
2309231200Smm		lastrm->props = NULL;
2310231200Smm		return (lastrm->end(a, lastrm));
2311231200Smm	}
2312231200Smm	return (ARCHIVE_OK);
2313231200Smm}
2314231200Smm
2315231200Smm
2316