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