archive_write_set_format_7zip.c revision 248616
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.
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,
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
1361231200Smm	/* Write Nume 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
1453231200Smm	file_free_register(zip);
1454231200Smm	compression_end(&(a->archive), &(zip->stream));
1455231200Smm	free(zip->coder.props);
1456231200Smm	free(zip);
1457231200Smm
1458231200Smm	return (ARCHIVE_OK);
1459231200Smm}
1460231200Smm
1461231200Smmstatic int
1462231200Smmfile_cmp_node(const struct archive_rb_node *n1,
1463231200Smm    const struct archive_rb_node *n2)
1464231200Smm{
1465232153Smm	const struct file *f1 = (const struct file *)n1;
1466232153Smm	const struct file *f2 = (const struct file *)n2;
1467231200Smm
1468231200Smm	if (f1->name_len == f2->name_len)
1469231200Smm		return (memcmp(f1->utf16name, f2->utf16name, f1->name_len));
1470231200Smm	return (f1->name_len > f2->name_len)?1:-1;
1471231200Smm}
1472231200Smm
1473231200Smmstatic int
1474231200Smmfile_cmp_key(const struct archive_rb_node *n, const void *key)
1475231200Smm{
1476232153Smm	const struct file *f = (const struct file *)n;
1477231200Smm
1478231200Smm	return (f->name_len - *(const char *)key);
1479231200Smm}
1480231200Smm
1481231200Smmstatic int
1482231200Smmfile_new(struct archive_write *a, struct archive_entry *entry,
1483231200Smm    struct file **newfile)
1484231200Smm{
1485231200Smm	struct _7zip *zip;
1486231200Smm	struct file *file;
1487231200Smm	const char *u16;
1488231200Smm	size_t u16len;
1489231200Smm	int ret = ARCHIVE_OK;
1490231200Smm
1491231200Smm	zip = (struct _7zip *)a->format_data;
1492231200Smm	*newfile = NULL;
1493231200Smm
1494231200Smm	file = calloc(1, sizeof(*file));
1495231200Smm	if (file == NULL) {
1496231200Smm		archive_set_error(&a->archive, ENOMEM,
1497231200Smm		    "Can't allocate memory");
1498231200Smm		return (ARCHIVE_FATAL);
1499231200Smm	}
1500231200Smm
1501231200Smm	if (0 > archive_entry_pathname_l(entry, &u16, &u16len, zip->sconv)) {
1502231200Smm		if (errno == ENOMEM) {
1503238856Smm			free(file);
1504231200Smm			archive_set_error(&a->archive, ENOMEM,
1505231200Smm			    "Can't allocate memory for UTF-16LE");
1506231200Smm			return (ARCHIVE_FATAL);
1507231200Smm		}
1508231200Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1509231200Smm		    "A filename cannot be converted to UTF-16LE;"
1510231200Smm		    "You should disable making Joliet extension");
1511231200Smm		ret = ARCHIVE_WARN;
1512231200Smm	}
1513231200Smm	file->utf16name = malloc(u16len + 2);
1514231200Smm	if (file->utf16name == NULL) {
1515238856Smm		free(file);
1516231200Smm		archive_set_error(&a->archive, ENOMEM,
1517231200Smm		    "Can't allocate memory for Name");
1518231200Smm		return (ARCHIVE_FATAL);
1519231200Smm	}
1520231200Smm	memcpy(file->utf16name, u16, u16len);
1521231200Smm	file->utf16name[u16len+0] = 0;
1522231200Smm	file->utf16name[u16len+1] = 0;
1523248616Smm	file->name_len = (unsigned)u16len;
1524231200Smm	file->mode = archive_entry_mode(entry);
1525231200Smm	if (archive_entry_filetype(entry) == AE_IFREG)
1526231200Smm		file->size = archive_entry_size(entry);
1527231200Smm	else
1528231200Smm		archive_entry_set_size(entry, 0);
1529231200Smm	if (archive_entry_filetype(entry) == AE_IFDIR)
1530231200Smm		file->dir = 1;
1531231200Smm	else if (archive_entry_filetype(entry) == AE_IFLNK)
1532231200Smm		file->size = strlen(archive_entry_symlink(entry));
1533231200Smm	if (archive_entry_mtime_is_set(entry)) {
1534231200Smm		file->flg |= MTIME_IS_SET;
1535231200Smm		file->times[MTIME].time = archive_entry_mtime(entry);
1536231200Smm		file->times[MTIME].time_ns = archive_entry_mtime_nsec(entry);
1537231200Smm	}
1538231200Smm	if (archive_entry_atime_is_set(entry)) {
1539231200Smm		file->flg |= ATIME_IS_SET;
1540231200Smm		file->times[ATIME].time = archive_entry_atime(entry);
1541231200Smm		file->times[ATIME].time_ns = archive_entry_atime_nsec(entry);
1542231200Smm	}
1543231200Smm	if (archive_entry_ctime_is_set(entry)) {
1544231200Smm		file->flg |= CTIME_IS_SET;
1545231200Smm		file->times[CTIME].time = archive_entry_ctime(entry);
1546231200Smm		file->times[CTIME].time_ns = archive_entry_ctime_nsec(entry);
1547231200Smm	}
1548231200Smm
1549231200Smm	*newfile = file;
1550231200Smm	return (ret);
1551231200Smm}
1552231200Smm
1553231200Smmstatic void
1554231200Smmfile_free(struct file *file)
1555231200Smm{
1556231200Smm	free(file->utf16name);
1557231200Smm	free(file);
1558231200Smm}
1559231200Smm
1560231200Smmstatic void
1561231200Smmfile_register(struct _7zip *zip, struct file *file)
1562231200Smm{
1563231200Smm	file->next = NULL;
1564231200Smm	*zip->file_list.last = file;
1565231200Smm	zip->file_list.last = &(file->next);
1566231200Smm}
1567231200Smm
1568231200Smmstatic void
1569231200Smmfile_init_register(struct _7zip *zip)
1570231200Smm{
1571231200Smm	zip->file_list.first = NULL;
1572231200Smm	zip->file_list.last = &(zip->file_list.first);
1573231200Smm}
1574231200Smm
1575231200Smmstatic void
1576231200Smmfile_free_register(struct _7zip *zip)
1577231200Smm{
1578231200Smm	struct file *file, *file_next;
1579231200Smm
1580231200Smm	file = zip->file_list.first;
1581231200Smm	while (file != NULL) {
1582231200Smm		file_next = file->next;
1583231200Smm		file_free(file);
1584231200Smm		file = file_next;
1585231200Smm	}
1586231200Smm}
1587231200Smm
1588231200Smmstatic void
1589231200Smmfile_register_empty(struct _7zip *zip, struct file *file)
1590231200Smm{
1591231200Smm	file->next = NULL;
1592231200Smm	*zip->empty_list.last = file;
1593231200Smm	zip->empty_list.last = &(file->next);
1594231200Smm}
1595231200Smm
1596231200Smmstatic void
1597231200Smmfile_init_register_empty(struct _7zip *zip)
1598231200Smm{
1599231200Smm	zip->empty_list.first = NULL;
1600231200Smm	zip->empty_list.last = &(zip->empty_list.first);
1601231200Smm}
1602231200Smm
1603232153Smm#if !defined(HAVE_ZLIB_H) || !defined(HAVE_BZLIB_H) ||\
1604232153Smm	 !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
1605231200Smmstatic int
1606231200Smmcompression_unsupported_encoder(struct archive *a,
1607231200Smm    struct la_zstream *lastrm, const char *name)
1608231200Smm{
1609231200Smm
1610231200Smm	archive_set_error(a, ARCHIVE_ERRNO_MISC,
1611231200Smm	    "%s compression not supported on this platform", name);
1612231200Smm	lastrm->valid = 0;
1613231200Smm	lastrm->real_stream = NULL;
1614231200Smm	return (ARCHIVE_FAILED);
1615231200Smm}
1616231200Smm#endif
1617231200Smm
1618231200Smm/*
1619231200Smm * _7_COPY compressor.
1620231200Smm */
1621231200Smmstatic int
1622231200Smmcompression_init_encoder_copy(struct archive *a, struct la_zstream *lastrm)
1623231200Smm{
1624231200Smm
1625231200Smm	if (lastrm->valid)
1626231200Smm		compression_end(a, lastrm);
1627231200Smm	lastrm->valid = 1;
1628231200Smm	lastrm->code = compression_code_copy;
1629231200Smm	lastrm->end = compression_end_copy;
1630231200Smm	return (ARCHIVE_OK);
1631231200Smm}
1632231200Smm
1633231200Smmstatic int
1634231200Smmcompression_code_copy(struct archive *a,
1635231200Smm    struct la_zstream *lastrm, enum la_zaction action)
1636231200Smm{
1637231200Smm	size_t bytes;
1638231200Smm
1639231200Smm	(void)a; /* UNUSED */
1640231200Smm	if (lastrm->avail_out > lastrm->avail_in)
1641231200Smm		bytes = lastrm->avail_in;
1642231200Smm	else
1643231200Smm		bytes = lastrm->avail_out;
1644231200Smm	if (bytes) {
1645231200Smm		memcpy(lastrm->next_out, lastrm->next_in, bytes);
1646231200Smm		lastrm->next_in += bytes;
1647231200Smm		lastrm->avail_in -= bytes;
1648231200Smm		lastrm->total_in += bytes;
1649231200Smm		lastrm->next_out += bytes;
1650231200Smm		lastrm->avail_out -= bytes;
1651231200Smm		lastrm->total_out += bytes;
1652231200Smm	}
1653231200Smm	if (action == ARCHIVE_Z_FINISH && lastrm->avail_in == 0)
1654231200Smm		return (ARCHIVE_EOF);
1655231200Smm	return (ARCHIVE_OK);
1656231200Smm}
1657231200Smm
1658231200Smmstatic int
1659231200Smmcompression_end_copy(struct archive *a, struct la_zstream *lastrm)
1660231200Smm{
1661231200Smm	(void)a; /* UNUSED */
1662231200Smm	lastrm->valid = 0;
1663231200Smm	return (ARCHIVE_OK);
1664231200Smm}
1665231200Smm
1666231200Smm/*
1667231200Smm * _7_DEFLATE compressor.
1668231200Smm */
1669231200Smm#ifdef HAVE_ZLIB_H
1670231200Smmstatic int
1671231200Smmcompression_init_encoder_deflate(struct archive *a,
1672231200Smm    struct la_zstream *lastrm, int level, int withheader)
1673231200Smm{
1674231200Smm	z_stream *strm;
1675231200Smm
1676231200Smm	if (lastrm->valid)
1677231200Smm		compression_end(a, lastrm);
1678231200Smm	strm = calloc(1, sizeof(*strm));
1679231200Smm	if (strm == NULL) {
1680231200Smm		archive_set_error(a, ENOMEM,
1681231200Smm		    "Can't allocate memory for gzip stream");
1682231200Smm		return (ARCHIVE_FATAL);
1683231200Smm	}
1684231200Smm	/* zlib.h is not const-correct, so we need this one bit
1685231200Smm	 * of ugly hackery to convert a const * pointer to
1686231200Smm	 * a non-const pointer. */
1687231200Smm	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
1688248616Smm	strm->avail_in = (uInt)lastrm->avail_in;
1689238856Smm	strm->total_in = (uLong)lastrm->total_in;
1690231200Smm	strm->next_out = lastrm->next_out;
1691248616Smm	strm->avail_out = (uInt)lastrm->avail_out;
1692238856Smm	strm->total_out = (uLong)lastrm->total_out;
1693231200Smm	if (deflateInit2(strm, level, Z_DEFLATED,
1694231200Smm	    (withheader)?15:-15,
1695231200Smm	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
1696231200Smm		free(strm);
1697231200Smm		lastrm->real_stream = NULL;
1698231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1699231200Smm		    "Internal error initializing compression library");
1700231200Smm		return (ARCHIVE_FATAL);
1701231200Smm	}
1702231200Smm	lastrm->real_stream = strm;
1703231200Smm	lastrm->valid = 1;
1704231200Smm	lastrm->code = compression_code_deflate;
1705231200Smm	lastrm->end = compression_end_deflate;
1706231200Smm	return (ARCHIVE_OK);
1707231200Smm}
1708231200Smm
1709231200Smmstatic int
1710231200Smmcompression_code_deflate(struct archive *a,
1711231200Smm    struct la_zstream *lastrm, enum la_zaction action)
1712231200Smm{
1713231200Smm	z_stream *strm;
1714231200Smm	int r;
1715231200Smm
1716231200Smm	strm = (z_stream *)lastrm->real_stream;
1717231200Smm	/* zlib.h is not const-correct, so we need this one bit
1718231200Smm	 * of ugly hackery to convert a const * pointer to
1719231200Smm	 * a non-const pointer. */
1720231200Smm	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
1721248616Smm	strm->avail_in = (uInt)lastrm->avail_in;
1722238856Smm	strm->total_in = (uLong)lastrm->total_in;
1723231200Smm	strm->next_out = lastrm->next_out;
1724248616Smm	strm->avail_out = (uInt)lastrm->avail_out;
1725238856Smm	strm->total_out = (uLong)lastrm->total_out;
1726231200Smm	r = deflate(strm,
1727231200Smm	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
1728231200Smm	lastrm->next_in = strm->next_in;
1729231200Smm	lastrm->avail_in = strm->avail_in;
1730231200Smm	lastrm->total_in = strm->total_in;
1731231200Smm	lastrm->next_out = strm->next_out;
1732231200Smm	lastrm->avail_out = strm->avail_out;
1733231200Smm	lastrm->total_out = strm->total_out;
1734231200Smm	switch (r) {
1735231200Smm	case Z_OK:
1736231200Smm		return (ARCHIVE_OK);
1737231200Smm	case Z_STREAM_END:
1738231200Smm		return (ARCHIVE_EOF);
1739231200Smm	default:
1740231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1741231200Smm		    "GZip compression failed:"
1742231200Smm		    " deflate() call returned status %d", r);
1743231200Smm		return (ARCHIVE_FATAL);
1744231200Smm	}
1745231200Smm}
1746231200Smm
1747231200Smmstatic int
1748231200Smmcompression_end_deflate(struct archive *a, struct la_zstream *lastrm)
1749231200Smm{
1750231200Smm	z_stream *strm;
1751231200Smm	int r;
1752231200Smm
1753231200Smm	strm = (z_stream *)lastrm->real_stream;
1754231200Smm	r = deflateEnd(strm);
1755231200Smm	free(strm);
1756231200Smm	lastrm->real_stream = NULL;
1757231200Smm	lastrm->valid = 0;
1758231200Smm	if (r != Z_OK) {
1759231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1760231200Smm		    "Failed to clean up compressor");
1761231200Smm		return (ARCHIVE_FATAL);
1762231200Smm	}
1763231200Smm	return (ARCHIVE_OK);
1764231200Smm}
1765231200Smm#else
1766231200Smmstatic int
1767231200Smmcompression_init_encoder_deflate(struct archive *a,
1768231200Smm    struct la_zstream *lastrm, int level, int withheader)
1769231200Smm{
1770231200Smm
1771231200Smm	(void) level; /* UNUSED */
1772231200Smm	(void) withheader; /* UNUSED */
1773231200Smm	if (lastrm->valid)
1774231200Smm		compression_end(a, lastrm);
1775231200Smm	return (compression_unsupported_encoder(a, lastrm, "deflate"));
1776231200Smm}
1777231200Smm#endif
1778231200Smm
1779231200Smm/*
1780231200Smm * _7_BZIP2 compressor.
1781231200Smm */
1782231200Smm#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
1783231200Smmstatic int
1784231200Smmcompression_init_encoder_bzip2(struct archive *a,
1785231200Smm    struct la_zstream *lastrm, int level)
1786231200Smm{
1787231200Smm	bz_stream *strm;
1788231200Smm
1789231200Smm	if (lastrm->valid)
1790231200Smm		compression_end(a, lastrm);
1791231200Smm	strm = calloc(1, sizeof(*strm));
1792231200Smm	if (strm == NULL) {
1793231200Smm		archive_set_error(a, ENOMEM,
1794231200Smm		    "Can't allocate memory for bzip2 stream");
1795231200Smm		return (ARCHIVE_FATAL);
1796231200Smm	}
1797231200Smm	/* bzlib.h is not const-correct, so we need this one bit
1798231200Smm	 * of ugly hackery to convert a const * pointer to
1799231200Smm	 * a non-const pointer. */
1800231200Smm	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
1801231200Smm	strm->avail_in = lastrm->avail_in;
1802231200Smm	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
1803231200Smm	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
1804231200Smm	strm->next_out = (char *)lastrm->next_out;
1805231200Smm	strm->avail_out = lastrm->avail_out;
1806231200Smm	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
1807231200Smm	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
1808231200Smm	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
1809231200Smm		free(strm);
1810231200Smm		lastrm->real_stream = NULL;
1811231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1812231200Smm		    "Internal error initializing compression library");
1813231200Smm		return (ARCHIVE_FATAL);
1814231200Smm	}
1815231200Smm	lastrm->real_stream = strm;
1816231200Smm	lastrm->valid = 1;
1817231200Smm	lastrm->code = compression_code_bzip2;
1818231200Smm	lastrm->end = compression_end_bzip2;
1819231200Smm	return (ARCHIVE_OK);
1820231200Smm}
1821231200Smm
1822231200Smmstatic int
1823231200Smmcompression_code_bzip2(struct archive *a,
1824231200Smm    struct la_zstream *lastrm, enum la_zaction action)
1825231200Smm{
1826231200Smm	bz_stream *strm;
1827231200Smm	int r;
1828231200Smm
1829231200Smm	strm = (bz_stream *)lastrm->real_stream;
1830231200Smm	/* bzlib.h is not const-correct, so we need this one bit
1831231200Smm	 * of ugly hackery to convert a const * pointer to
1832231200Smm	 * a non-const pointer. */
1833231200Smm	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
1834231200Smm	strm->avail_in = lastrm->avail_in;
1835231200Smm	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
1836231200Smm	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
1837231200Smm	strm->next_out = (char *)lastrm->next_out;
1838231200Smm	strm->avail_out = lastrm->avail_out;
1839231200Smm	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
1840231200Smm	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
1841231200Smm	r = BZ2_bzCompress(strm,
1842231200Smm	    (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
1843231200Smm	lastrm->next_in = (const unsigned char *)strm->next_in;
1844231200Smm	lastrm->avail_in = strm->avail_in;
1845231200Smm	lastrm->total_in =
1846231200Smm	    (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
1847231200Smm	    + (uint64_t)(uint32_t)strm->total_in_lo32;
1848231200Smm	lastrm->next_out = (unsigned char *)strm->next_out;
1849231200Smm	lastrm->avail_out = strm->avail_out;
1850231200Smm	lastrm->total_out =
1851231200Smm	    (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
1852231200Smm	    + (uint64_t)(uint32_t)strm->total_out_lo32;
1853231200Smm	switch (r) {
1854231200Smm	case BZ_RUN_OK:     /* Non-finishing */
1855231200Smm	case BZ_FINISH_OK:  /* Finishing: There's more work to do */
1856231200Smm		return (ARCHIVE_OK);
1857231200Smm	case BZ_STREAM_END: /* Finishing: all done */
1858231200Smm		/* Only occurs in finishing case */
1859231200Smm		return (ARCHIVE_EOF);
1860231200Smm	default:
1861231200Smm		/* Any other return value indicates an error */
1862231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1863231200Smm		    "Bzip2 compression failed:"
1864231200Smm		    " BZ2_bzCompress() call returned status %d", r);
1865231200Smm		return (ARCHIVE_FATAL);
1866231200Smm	}
1867231200Smm}
1868231200Smm
1869231200Smmstatic int
1870231200Smmcompression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
1871231200Smm{
1872231200Smm	bz_stream *strm;
1873231200Smm	int r;
1874231200Smm
1875231200Smm	strm = (bz_stream *)lastrm->real_stream;
1876231200Smm	r = BZ2_bzCompressEnd(strm);
1877231200Smm	free(strm);
1878231200Smm	lastrm->real_stream = NULL;
1879231200Smm	lastrm->valid = 0;
1880231200Smm	if (r != BZ_OK) {
1881231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1882231200Smm		    "Failed to clean up compressor");
1883231200Smm		return (ARCHIVE_FATAL);
1884231200Smm	}
1885231200Smm	return (ARCHIVE_OK);
1886231200Smm}
1887231200Smm
1888231200Smm#else
1889231200Smmstatic int
1890231200Smmcompression_init_encoder_bzip2(struct archive *a,
1891231200Smm    struct la_zstream *lastrm, int level)
1892231200Smm{
1893231200Smm
1894231200Smm	(void) level; /* UNUSED */
1895231200Smm	if (lastrm->valid)
1896231200Smm		compression_end(a, lastrm);
1897231200Smm	return (compression_unsupported_encoder(a, lastrm, "bzip2"));
1898231200Smm}
1899231200Smm#endif
1900231200Smm
1901231200Smm/*
1902231200Smm * _7_LZMA1, _7_LZMA2 compressor.
1903231200Smm */
1904231200Smm#if defined(HAVE_LZMA_H)
1905231200Smmstatic int
1906231200Smmcompression_init_encoder_lzma(struct archive *a,
1907231200Smm    struct la_zstream *lastrm, int level, uint64_t filter_id)
1908231200Smm{
1909231200Smm	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
1910231200Smm	lzma_stream *strm;
1911231200Smm	lzma_filter *lzmafilters;
1912231200Smm	lzma_options_lzma lzma_opt;
1913231200Smm	int r;
1914231200Smm
1915231200Smm	if (lastrm->valid)
1916231200Smm		compression_end(a, lastrm);
1917231200Smm	strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
1918231200Smm	if (strm == NULL) {
1919231200Smm		archive_set_error(a, ENOMEM,
1920231200Smm		    "Can't allocate memory for lzma stream");
1921231200Smm		return (ARCHIVE_FATAL);
1922231200Smm	}
1923231200Smm	lzmafilters = (lzma_filter *)(strm+1);
1924231200Smm	if (level > 6)
1925231200Smm		level = 6;
1926231200Smm	if (lzma_lzma_preset(&lzma_opt, level)) {
1927238856Smm		free(strm);
1928231200Smm		lastrm->real_stream = NULL;
1929231200Smm		archive_set_error(a, ENOMEM,
1930231200Smm		    "Internal error initializing compression library");
1931231200Smm		return (ARCHIVE_FATAL);
1932231200Smm	}
1933231200Smm	lzmafilters[0].id = filter_id;
1934231200Smm	lzmafilters[0].options = &lzma_opt;
1935231200Smm	lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
1936231200Smm
1937231200Smm	r = lzma_properties_size(&(lastrm->prop_size), lzmafilters);
1938231200Smm	if (r != LZMA_OK) {
1939231200Smm		free(strm);
1940231200Smm		lastrm->real_stream = NULL;
1941231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1942231200Smm		    "lzma_properties_size failed");
1943231200Smm		return (ARCHIVE_FATAL);
1944231200Smm	}
1945231200Smm	if (lastrm->prop_size) {
1946231200Smm		lastrm->props = malloc(lastrm->prop_size);
1947231200Smm		if (lastrm->props == NULL) {
1948231200Smm			free(strm);
1949231200Smm			lastrm->real_stream = NULL;
1950231200Smm			archive_set_error(a, ENOMEM,
1951231200Smm			    "Cannot allocate memory");
1952231200Smm			return (ARCHIVE_FATAL);
1953231200Smm		}
1954231200Smm		r = lzma_properties_encode(lzmafilters,  lastrm->props);
1955231200Smm		if (r != LZMA_OK) {
1956231200Smm			free(strm);
1957231200Smm			lastrm->real_stream = NULL;
1958231200Smm			archive_set_error(a, ARCHIVE_ERRNO_MISC,
1959231200Smm			    "lzma_properties_encode failed");
1960231200Smm			return (ARCHIVE_FATAL);
1961231200Smm		}
1962231200Smm	}
1963231200Smm
1964231200Smm	*strm = lzma_init_data;
1965231200Smm	r = lzma_raw_encoder(strm, lzmafilters);
1966231200Smm	switch (r) {
1967231200Smm	case LZMA_OK:
1968231200Smm		lastrm->real_stream = strm;
1969231200Smm		lastrm->valid = 1;
1970231200Smm		lastrm->code = compression_code_lzma;
1971231200Smm		lastrm->end = compression_end_lzma;
1972231200Smm		r = ARCHIVE_OK;
1973231200Smm		break;
1974231200Smm	case LZMA_MEM_ERROR:
1975231200Smm		free(strm);
1976231200Smm		lastrm->real_stream = NULL;
1977231200Smm		archive_set_error(a, ENOMEM,
1978231200Smm		    "Internal error initializing compression library: "
1979231200Smm		    "Cannot allocate memory");
1980231200Smm		r =  ARCHIVE_FATAL;
1981231200Smm		break;
1982231200Smm        default:
1983231200Smm		free(strm);
1984231200Smm		lastrm->real_stream = NULL;
1985231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
1986231200Smm		    "Internal error initializing compression library: "
1987231200Smm		    "It's a bug in liblzma");
1988231200Smm		r =  ARCHIVE_FATAL;
1989231200Smm		break;
1990231200Smm	}
1991231200Smm	return (r);
1992231200Smm}
1993231200Smm
1994231200Smmstatic int
1995231200Smmcompression_init_encoder_lzma1(struct archive *a,
1996231200Smm    struct la_zstream *lastrm, int level)
1997231200Smm{
1998231200Smm	return compression_init_encoder_lzma(a, lastrm, level,
1999231200Smm		    LZMA_FILTER_LZMA1);
2000231200Smm}
2001231200Smm
2002231200Smmstatic int
2003231200Smmcompression_init_encoder_lzma2(struct archive *a,
2004231200Smm    struct la_zstream *lastrm, int level)
2005231200Smm{
2006231200Smm	return compression_init_encoder_lzma(a, lastrm, level,
2007231200Smm		    LZMA_FILTER_LZMA2);
2008231200Smm}
2009231200Smm
2010231200Smmstatic int
2011231200Smmcompression_code_lzma(struct archive *a,
2012231200Smm    struct la_zstream *lastrm, enum la_zaction action)
2013231200Smm{
2014231200Smm	lzma_stream *strm;
2015231200Smm	int r;
2016231200Smm
2017231200Smm	strm = (lzma_stream *)lastrm->real_stream;
2018231200Smm	strm->next_in = lastrm->next_in;
2019231200Smm	strm->avail_in = lastrm->avail_in;
2020231200Smm	strm->total_in = lastrm->total_in;
2021231200Smm	strm->next_out = lastrm->next_out;
2022231200Smm	strm->avail_out = lastrm->avail_out;
2023231200Smm	strm->total_out = lastrm->total_out;
2024231200Smm	r = lzma_code(strm,
2025231200Smm	    (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
2026231200Smm	lastrm->next_in = strm->next_in;
2027231200Smm	lastrm->avail_in = strm->avail_in;
2028231200Smm	lastrm->total_in = strm->total_in;
2029231200Smm	lastrm->next_out = strm->next_out;
2030231200Smm	lastrm->avail_out = strm->avail_out;
2031231200Smm	lastrm->total_out = strm->total_out;
2032231200Smm	switch (r) {
2033231200Smm	case LZMA_OK:
2034231200Smm		/* Non-finishing case */
2035231200Smm		return (ARCHIVE_OK);
2036231200Smm	case LZMA_STREAM_END:
2037231200Smm		/* This return can only occur in finishing case. */
2038231200Smm		return (ARCHIVE_EOF);
2039231200Smm	case LZMA_MEMLIMIT_ERROR:
2040231200Smm		archive_set_error(a, ENOMEM,
2041231200Smm		    "lzma compression error:"
2042231200Smm		    " %ju MiB would have been needed",
2043231200Smm		    (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
2044231200Smm			/ (1024 * 1024)));
2045231200Smm		return (ARCHIVE_FATAL);
2046231200Smm	default:
2047231200Smm		/* Any other return value indicates an error */
2048231200Smm		archive_set_error(a, ARCHIVE_ERRNO_MISC,
2049231200Smm		    "lzma compression failed:"
2050231200Smm		    " lzma_code() call returned status %d", r);
2051231200Smm		return (ARCHIVE_FATAL);
2052231200Smm	}
2053231200Smm}
2054231200Smm
2055231200Smmstatic int
2056231200Smmcompression_end_lzma(struct archive *a, struct la_zstream *lastrm)
2057231200Smm{
2058231200Smm	lzma_stream *strm;
2059231200Smm
2060231200Smm	(void)a; /* UNUSED */
2061231200Smm	strm = (lzma_stream *)lastrm->real_stream;
2062231200Smm	lzma_end(strm);
2063231200Smm	free(strm);
2064231200Smm	lastrm->valid = 0;
2065231200Smm	lastrm->real_stream = NULL;
2066231200Smm	return (ARCHIVE_OK);
2067231200Smm}
2068231200Smm#else
2069231200Smmstatic int
2070231200Smmcompression_init_encoder_lzma1(struct archive *a,
2071231200Smm    struct la_zstream *lastrm, int level)
2072231200Smm{
2073231200Smm
2074231200Smm	(void) level; /* UNUSED */
2075231200Smm	if (lastrm->valid)
2076231200Smm		compression_end(a, lastrm);
2077231200Smm	return (compression_unsupported_encoder(a, lastrm, "lzma"));
2078231200Smm}
2079231200Smmstatic int
2080231200Smmcompression_init_encoder_lzma2(struct archive *a,
2081231200Smm    struct la_zstream *lastrm, int level)
2082231200Smm{
2083231200Smm
2084231200Smm	(void) level; /* UNUSED */
2085231200Smm	if (lastrm->valid)
2086231200Smm		compression_end(a, lastrm);
2087231200Smm	return (compression_unsupported_encoder(a, lastrm, "lzma"));
2088231200Smm}
2089231200Smm#endif
2090231200Smm
2091231200Smm/*
2092231200Smm * _7_PPMD compressor.
2093231200Smm */
2094231200Smmstatic void *
2095231200Smmppmd_alloc(void *p, size_t size)
2096231200Smm{
2097231200Smm	(void)p;
2098231200Smm	return malloc(size);
2099231200Smm}
2100231200Smmstatic void
2101231200Smmppmd_free(void *p, void *address)
2102231200Smm{
2103231200Smm	(void)p;
2104231200Smm	free(address);
2105231200Smm}
2106231200Smmstatic ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
2107231200Smmstatic void
2108231200Smmppmd_write(void *p, Byte b)
2109231200Smm{
2110231200Smm	struct archive_write *a = ((IByteOut *)p)->a;
2111231200Smm	struct _7zip *zip = (struct _7zip *)(a->format_data);
2112231200Smm	struct la_zstream *lastrm = &(zip->stream);
2113231200Smm	struct ppmd_stream *strm;
2114231200Smm
2115231200Smm	if (lastrm->avail_out) {
2116231200Smm		*lastrm->next_out++ = b;
2117231200Smm		lastrm->avail_out--;
2118231200Smm		lastrm->total_out++;
2119231200Smm		return;
2120231200Smm	}
2121231200Smm	strm = (struct ppmd_stream *)lastrm->real_stream;
2122231200Smm	if (strm->buff_ptr < strm->buff_end) {
2123231200Smm		*strm->buff_ptr++ = b;
2124231200Smm		strm->buff_bytes++;
2125231200Smm	}
2126231200Smm}
2127231200Smm
2128231200Smmstatic int
2129231200Smmcompression_init_encoder_ppmd(struct archive *a,
2130231200Smm    struct la_zstream *lastrm, unsigned maxOrder, uint32_t msize)
2131231200Smm{
2132231200Smm	struct ppmd_stream *strm;
2133231200Smm	uint8_t *props;
2134231200Smm	int r;
2135231200Smm
2136231200Smm	if (lastrm->valid)
2137231200Smm		compression_end(a, lastrm);
2138231200Smm	strm = calloc(1, sizeof(*strm));
2139231200Smm	if (strm == NULL) {
2140231200Smm		archive_set_error(a, ENOMEM,
2141231200Smm		    "Can't allocate memory for PPMd");
2142231200Smm		return (ARCHIVE_FATAL);
2143231200Smm	}
2144231200Smm	strm->buff = malloc(32);
2145231200Smm	if (strm->buff == NULL) {
2146231200Smm		free(strm);
2147231200Smm		archive_set_error(a, ENOMEM,
2148231200Smm		    "Can't allocate memory for PPMd");
2149231200Smm		return (ARCHIVE_FATAL);
2150231200Smm	}
2151231200Smm	strm->buff_ptr = strm->buff;
2152231200Smm	strm->buff_end = strm->buff + 32;
2153231200Smm
2154231200Smm	props = malloc(1+4);
2155231200Smm	if (props == NULL) {
2156231200Smm		free(strm->buff);
2157231200Smm		free(strm);
2158231200Smm		archive_set_error(a, ENOMEM,
2159231200Smm		    "Coludn't allocate memory for PPMd");
2160231200Smm		return (ARCHIVE_FATAL);
2161231200Smm	}
2162231200Smm	props[0] = maxOrder;
2163231200Smm	archive_le32enc(props+1, msize);
2164231200Smm	__archive_ppmd7_functions.Ppmd7_Construct(&strm->ppmd7_context);
2165231200Smm	r = __archive_ppmd7_functions.Ppmd7_Alloc(
2166231200Smm		&strm->ppmd7_context, msize, &g_szalloc);
2167231200Smm	if (r == 0) {
2168231200Smm		free(strm->buff);
2169231200Smm		free(strm);
2170231200Smm		free(props);
2171231200Smm		archive_set_error(a, ENOMEM,
2172231200Smm		    "Coludn't allocate memory for PPMd");
2173231200Smm		return (ARCHIVE_FATAL);
2174231200Smm	}
2175231200Smm	__archive_ppmd7_functions.Ppmd7_Init(&(strm->ppmd7_context), maxOrder);
2176231200Smm	strm->byteout.a = (struct archive_write *)a;
2177231200Smm	strm->byteout.Write = ppmd_write;
2178231200Smm	strm->range_enc.Stream = &(strm->byteout);
2179231200Smm	__archive_ppmd7_functions.Ppmd7z_RangeEnc_Init(&(strm->range_enc));
2180231200Smm	strm->stat = 0;
2181231200Smm
2182231200Smm	lastrm->real_stream = strm;
2183231200Smm	lastrm->valid = 1;
2184231200Smm	lastrm->code = compression_code_ppmd;
2185231200Smm	lastrm->end = compression_end_ppmd;
2186231200Smm	lastrm->prop_size = 5;
2187231200Smm	lastrm->props = props;
2188231200Smm	return (ARCHIVE_OK);
2189231200Smm}
2190231200Smm
2191231200Smmstatic int
2192231200Smmcompression_code_ppmd(struct archive *a,
2193231200Smm    struct la_zstream *lastrm, enum la_zaction action)
2194231200Smm{
2195231200Smm	struct ppmd_stream *strm;
2196231200Smm
2197232153Smm	(void)a; /* UNUSED */
2198232153Smm
2199231200Smm	strm = (struct ppmd_stream *)lastrm->real_stream;
2200231200Smm
2201231200Smm	/* Copy encoded data if there are remaining bytes from previous call. */
2202231200Smm	if (strm->buff_bytes) {
2203231200Smm		uint8_t *p = strm->buff_ptr - strm->buff_bytes;
2204231200Smm		while (lastrm->avail_out && strm->buff_bytes) {
2205231200Smm			*lastrm->next_out++ = *p++;
2206231200Smm			lastrm->avail_out--;
2207231200Smm			lastrm->total_out++;
2208231200Smm			strm->buff_bytes--;
2209231200Smm		}
2210231200Smm		if (strm->buff_bytes)
2211231200Smm			return (ARCHIVE_OK);
2212231200Smm		if (strm->stat == 1)
2213231200Smm			return (ARCHIVE_EOF);
2214231200Smm		strm->buff_ptr = strm->buff;
2215231200Smm	}
2216231200Smm	while (lastrm->avail_in && lastrm->avail_out) {
2217231200Smm		__archive_ppmd7_functions.Ppmd7_EncodeSymbol(
2218231200Smm			&(strm->ppmd7_context), &(strm->range_enc),
2219231200Smm			*lastrm->next_in++);
2220231200Smm		lastrm->avail_in--;
2221231200Smm		lastrm->total_in++;
2222231200Smm	}
2223231200Smm	if (lastrm->avail_in == 0 && action == ARCHIVE_Z_FINISH) {
2224231200Smm		__archive_ppmd7_functions.Ppmd7z_RangeEnc_FlushData(
2225231200Smm			&(strm->range_enc));
2226231200Smm		strm->stat = 1;
2227231200Smm		/* Return EOF if there are no remaining bytes. */
2228231200Smm		if (strm->buff_bytes == 0)
2229231200Smm			return (ARCHIVE_EOF);
2230231200Smm	}
2231231200Smm	return (ARCHIVE_OK);
2232231200Smm}
2233231200Smm
2234231200Smmstatic int
2235231200Smmcompression_end_ppmd(struct archive *a, struct la_zstream *lastrm)
2236231200Smm{
2237231200Smm	struct ppmd_stream *strm;
2238231200Smm
2239232153Smm	(void)a; /* UNUSED */
2240232153Smm
2241231200Smm	strm = (struct ppmd_stream *)lastrm->real_stream;
2242231200Smm	__archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context, &g_szalloc);
2243231200Smm	free(strm->buff);
2244231200Smm	free(strm);
2245231200Smm	lastrm->real_stream = NULL;
2246231200Smm	lastrm->valid = 0;
2247231200Smm	return (ARCHIVE_OK);
2248231200Smm}
2249231200Smm
2250231200Smm/*
2251231200Smm * Universal compressor initializer.
2252231200Smm */
2253231200Smmstatic int
2254231200Smm_7z_compression_init_encoder(struct archive_write *a, unsigned compression,
2255231200Smm    int compression_level)
2256231200Smm{
2257231200Smm	struct _7zip *zip;
2258231200Smm	int r;
2259231200Smm
2260231200Smm	zip = (struct _7zip *)a->format_data;
2261231200Smm	switch (compression) {
2262231200Smm	case _7Z_DEFLATE:
2263231200Smm		r = compression_init_encoder_deflate(
2264231200Smm		    &(a->archive), &(zip->stream),
2265231200Smm		    compression_level, 0);
2266231200Smm		break;
2267231200Smm	case _7Z_BZIP2:
2268231200Smm		r = compression_init_encoder_bzip2(
2269231200Smm		    &(a->archive), &(zip->stream),
2270231200Smm		    compression_level);
2271231200Smm		break;
2272231200Smm	case _7Z_LZMA1:
2273231200Smm		r = compression_init_encoder_lzma1(
2274231200Smm		    &(a->archive), &(zip->stream),
2275231200Smm		    compression_level);
2276231200Smm		break;
2277231200Smm	case _7Z_LZMA2:
2278231200Smm		r = compression_init_encoder_lzma2(
2279231200Smm		    &(a->archive), &(zip->stream),
2280231200Smm		    compression_level);
2281231200Smm		break;
2282231200Smm	case _7Z_PPMD:
2283231200Smm		r = compression_init_encoder_ppmd(
2284231200Smm		    &(a->archive), &(zip->stream),
2285231200Smm		    PPMD7_DEFAULT_ORDER, PPMD7_DEFAULT_MEM_SIZE);
2286231200Smm		break;
2287231200Smm	case _7Z_COPY:
2288231200Smm	default:
2289231200Smm		r = compression_init_encoder_copy(
2290231200Smm		    &(a->archive), &(zip->stream));
2291231200Smm		break;
2292231200Smm	}
2293231200Smm	if (r == ARCHIVE_OK) {
2294231200Smm		zip->stream.total_in = 0;
2295231200Smm		zip->stream.next_out = zip->wbuff;
2296231200Smm		zip->stream.avail_out = sizeof(zip->wbuff);
2297231200Smm		zip->stream.total_out = 0;
2298231200Smm	}
2299231200Smm
2300231200Smm	return (r);
2301231200Smm}
2302231200Smm
2303231200Smmstatic int
2304231200Smmcompression_code(struct archive *a, struct la_zstream *lastrm,
2305231200Smm    enum la_zaction action)
2306231200Smm{
2307231200Smm	if (lastrm->valid)
2308231200Smm		return (lastrm->code(a, lastrm, action));
2309231200Smm	return (ARCHIVE_OK);
2310231200Smm}
2311231200Smm
2312231200Smmstatic int
2313231200Smmcompression_end(struct archive *a, struct la_zstream *lastrm)
2314231200Smm{
2315231200Smm	if (lastrm->valid) {
2316231200Smm		lastrm->prop_size = 0;
2317231200Smm		free(lastrm->props);
2318231200Smm		lastrm->props = NULL;
2319231200Smm		return (lastrm->end(a, lastrm));
2320231200Smm	}
2321231200Smm	return (ARCHIVE_OK);
2322231200Smm}
2323231200Smm
2324231200Smm
2325