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