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