1228753Smm/*- 2231200Smm * Copyright (c) 2003-2010 Tim Kientzle 3232153Smm * Copyright (c) 2009-2012 Michihiro NAKAJIMA 4228753Smm * All rights reserved. 5228753Smm * 6228753Smm * Redistribution and use in source and binary forms, with or without 7228753Smm * modification, are permitted provided that the following conditions 8228753Smm * are met: 9228753Smm * 1. Redistributions of source code must retain the above copyright 10228753Smm * notice, this list of conditions and the following disclaimer. 11228753Smm * 2. Redistributions in binary form must reproduce the above copyright 12228753Smm * notice, this list of conditions and the following disclaimer in the 13228753Smm * documentation and/or other materials provided with the distribution. 14228753Smm * 15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25228753Smm */ 26228753Smm 27228753Smm#include "archive_platform.h" 28228753Smm 29228753Smm__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_xz.c 201108 2009-12-28 03:28:21Z kientzle $"); 30228753Smm 31228753Smm#ifdef HAVE_ERRNO_H 32228753Smm#include <errno.h> 33228753Smm#endif 34228753Smm#ifdef HAVE_STDLIB_H 35228753Smm#include <stdlib.h> 36228753Smm#endif 37228753Smm#ifdef HAVE_STRING_H 38228753Smm#include <string.h> 39228753Smm#endif 40228753Smm#include <time.h> 41228753Smm#ifdef HAVE_LZMA_H 42228753Smm#include <lzma.h> 43228753Smm#endif 44228753Smm 45228753Smm#include "archive.h" 46231200Smm#include "archive_endian.h" 47228753Smm#include "archive_private.h" 48228753Smm#include "archive_write_private.h" 49228753Smm 50231200Smm#if ARCHIVE_VERSION_NUMBER < 4000000 51228753Smmint 52231200Smmarchive_write_set_compression_lzip(struct archive *a) 53231200Smm{ 54231200Smm __archive_write_filters_free(a); 55231200Smm return (archive_write_add_filter_lzip(a)); 56231200Smm} 57231200Smm 58231200Smmint 59231200Smmarchive_write_set_compression_lzma(struct archive *a) 60231200Smm{ 61231200Smm __archive_write_filters_free(a); 62231200Smm return (archive_write_add_filter_lzma(a)); 63231200Smm} 64231200Smm 65231200Smmint 66228753Smmarchive_write_set_compression_xz(struct archive *a) 67228753Smm{ 68231200Smm __archive_write_filters_free(a); 69231200Smm return (archive_write_add_filter_xz(a)); 70231200Smm} 71231200Smm 72231200Smm#endif 73231200Smm 74231200Smm#ifndef HAVE_LZMA_H 75231200Smmint 76231200Smmarchive_write_add_filter_xz(struct archive *a) 77231200Smm{ 78228753Smm archive_set_error(a, ARCHIVE_ERRNO_MISC, 79228753Smm "xz compression not supported on this platform"); 80228753Smm return (ARCHIVE_FATAL); 81228753Smm} 82228753Smm 83228753Smmint 84231200Smmarchive_write_add_filter_lzma(struct archive *a) 85228753Smm{ 86228753Smm archive_set_error(a, ARCHIVE_ERRNO_MISC, 87228753Smm "lzma compression not supported on this platform"); 88228753Smm return (ARCHIVE_FATAL); 89228753Smm} 90231200Smm 91231200Smmint 92231200Smmarchive_write_add_filter_lzip(struct archive *a) 93231200Smm{ 94231200Smm archive_set_error(a, ARCHIVE_ERRNO_MISC, 95231200Smm "lzma compression not supported on this platform"); 96231200Smm return (ARCHIVE_FATAL); 97231200Smm} 98228753Smm#else 99228753Smm/* Don't compile this if we don't have liblzma. */ 100228753Smm 101228753Smmstruct private_data { 102231200Smm int compression_level; 103228753Smm lzma_stream stream; 104228753Smm lzma_filter lzmafilters[2]; 105228753Smm lzma_options_lzma lzma_opt; 106228753Smm int64_t total_in; 107228753Smm unsigned char *compressed; 108228753Smm size_t compressed_buffer_size; 109231200Smm int64_t total_out; 110231200Smm /* the CRC32 value of uncompressed data for lzip */ 111231200Smm uint32_t crc32; 112228753Smm}; 113228753Smm 114231200Smmstatic int archive_compressor_xz_options(struct archive_write_filter *, 115228753Smm const char *, const char *); 116231200Smmstatic int archive_compressor_xz_open(struct archive_write_filter *); 117231200Smmstatic int archive_compressor_xz_write(struct archive_write_filter *, 118228753Smm const void *, size_t); 119231200Smmstatic int archive_compressor_xz_close(struct archive_write_filter *); 120231200Smmstatic int archive_compressor_xz_free(struct archive_write_filter *); 121231200Smmstatic int drive_compressor(struct archive_write_filter *, 122231200Smm struct private_data *, int finishing); 123228753Smm 124231200Smmstruct option_value { 125231200Smm uint32_t dict_size; 126231200Smm uint32_t nice_len; 127231200Smm lzma_match_finder mf; 128231200Smm}; 129231200Smmstatic const struct option_value option_values[] = { 130231200Smm { 1 << 16, 32, LZMA_MF_HC3}, 131231200Smm { 1 << 20, 32, LZMA_MF_HC3}, 132231200Smm { 3 << 19, 32, LZMA_MF_HC4}, 133231200Smm { 1 << 21, 32, LZMA_MF_BT4}, 134231200Smm { 3 << 20, 32, LZMA_MF_BT4}, 135231200Smm { 1 << 22, 32, LZMA_MF_BT4}, 136231200Smm { 1 << 23, 64, LZMA_MF_BT4}, 137231200Smm { 1 << 24, 64, LZMA_MF_BT4}, 138231200Smm { 3 << 23, 64, LZMA_MF_BT4}, 139231200Smm { 1 << 25, 64, LZMA_MF_BT4} 140231200Smm}; 141228753Smm 142231200Smmstatic int 143231200Smmcommon_setup(struct archive_write_filter *f) 144228753Smm{ 145231200Smm struct private_data *data; 146231200Smm struct archive_write *a = (struct archive_write *)f->archive; 147231200Smm data = calloc(1, sizeof(*data)); 148231200Smm if (data == NULL) { 149228753Smm archive_set_error(&a->archive, ENOMEM, "Out of memory"); 150228753Smm return (ARCHIVE_FATAL); 151228753Smm } 152231200Smm f->data = data; 153231200Smm data->compression_level = LZMA_PRESET_DEFAULT; 154231200Smm f->open = &archive_compressor_xz_open; 155231200Smm f->close = archive_compressor_xz_close; 156231200Smm f->free = archive_compressor_xz_free; 157231200Smm f->options = &archive_compressor_xz_options; 158228753Smm return (ARCHIVE_OK); 159228753Smm} 160228753Smm 161231200Smm/* 162231200Smm * Add an xz compression filter to this write handle. 163231200Smm */ 164231200Smmint 165231200Smmarchive_write_add_filter_xz(struct archive *_a) 166231200Smm{ 167231200Smm struct archive_write_filter *f; 168231200Smm int r; 169231200Smm 170231200Smm archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 171231200Smm ARCHIVE_STATE_NEW, "archive_write_add_filter_xz"); 172231200Smm f = __archive_write_allocate_filter(_a); 173231200Smm r = common_setup(f); 174231200Smm if (r == ARCHIVE_OK) { 175248616Smm f->code = ARCHIVE_FILTER_XZ; 176231200Smm f->name = "xz"; 177231200Smm } 178231200Smm return (r); 179231200Smm} 180231200Smm 181228753Smm/* LZMA is handled identically, we just need a different compression 182228753Smm * code set. (The liblzma setup looks at the code to determine 183228753Smm * the one place that XZ and LZMA require different handling.) */ 184228753Smmint 185231200Smmarchive_write_add_filter_lzma(struct archive *_a) 186228753Smm{ 187231200Smm struct archive_write_filter *f; 188231200Smm int r; 189231200Smm 190231200Smm archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 191231200Smm ARCHIVE_STATE_NEW, "archive_write_add_filter_lzma"); 192231200Smm f = __archive_write_allocate_filter(_a); 193231200Smm r = common_setup(f); 194231200Smm if (r == ARCHIVE_OK) { 195248616Smm f->code = ARCHIVE_FILTER_LZMA; 196231200Smm f->name = "lzma"; 197231200Smm } 198231200Smm return (r); 199228753Smm} 200228753Smm 201231200Smmint 202231200Smmarchive_write_add_filter_lzip(struct archive *_a) 203231200Smm{ 204231200Smm struct archive_write_filter *f; 205231200Smm int r; 206231200Smm 207231200Smm archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 208231200Smm ARCHIVE_STATE_NEW, "archive_write_add_filter_lzip"); 209231200Smm f = __archive_write_allocate_filter(_a); 210231200Smm r = common_setup(f); 211231200Smm if (r == ARCHIVE_OK) { 212248616Smm f->code = ARCHIVE_FILTER_LZIP; 213231200Smm f->name = "lzip"; 214231200Smm } 215231200Smm return (r); 216231200Smm} 217231200Smm 218228753Smmstatic int 219231200Smmarchive_compressor_xz_init_stream(struct archive_write_filter *f, 220231200Smm struct private_data *data) 221228753Smm{ 222228753Smm static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT; 223228753Smm int ret; 224228753Smm 225231200Smm data->stream = lzma_stream_init_data; 226231200Smm data->stream.next_out = data->compressed; 227231200Smm data->stream.avail_out = data->compressed_buffer_size; 228248616Smm if (f->code == ARCHIVE_FILTER_XZ) 229231200Smm ret = lzma_stream_encoder(&(data->stream), 230231200Smm data->lzmafilters, LZMA_CHECK_CRC64); 231248616Smm else if (f->code == ARCHIVE_FILTER_LZMA) 232231200Smm ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt); 233248616Smm else { /* ARCHIVE_FILTER_LZIP */ 234231200Smm int dict_size = data->lzma_opt.dict_size; 235231200Smm int ds, log2dic, wedges; 236231200Smm 237231200Smm /* Calculate a coded dictionary size */ 238231200Smm if (dict_size < (1 << 12) || dict_size > (1 << 27)) { 239231200Smm archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 240231200Smm "Unacceptable dictionary dize for lzip: %d", 241231200Smm dict_size); 242231200Smm return (ARCHIVE_FATAL); 243231200Smm } 244231200Smm for (log2dic = 27; log2dic >= 12; log2dic--) { 245231200Smm if (dict_size & (1 << log2dic)) 246231200Smm break; 247231200Smm } 248231200Smm if (dict_size > (1 << log2dic)) { 249231200Smm log2dic++; 250231200Smm wedges = 251231200Smm ((1 << log2dic) - dict_size) / (1 << (log2dic - 4)); 252231200Smm } else 253231200Smm wedges = 0; 254231200Smm ds = ((wedges << 5) & 0xe0) | (log2dic & 0x1f); 255231200Smm 256231200Smm data->crc32 = 0; 257231200Smm /* Make a header */ 258231200Smm data->compressed[0] = 0x4C; 259231200Smm data->compressed[1] = 0x5A; 260231200Smm data->compressed[2] = 0x49; 261231200Smm data->compressed[3] = 0x50; 262231200Smm data->compressed[4] = 1;/* Version */ 263231200Smm data->compressed[5] = (unsigned char)ds; 264231200Smm data->stream.next_out += 6; 265231200Smm data->stream.avail_out -= 6; 266231200Smm 267231200Smm ret = lzma_raw_encoder(&(data->stream), data->lzmafilters); 268231200Smm } 269228753Smm if (ret == LZMA_OK) 270228753Smm return (ARCHIVE_OK); 271228753Smm 272228753Smm switch (ret) { 273228753Smm case LZMA_MEM_ERROR: 274231200Smm archive_set_error(f->archive, ENOMEM, 275228753Smm "Internal error initializing compression library: " 276228753Smm "Cannot allocate memory"); 277228753Smm break; 278228753Smm default: 279231200Smm archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 280228753Smm "Internal error initializing compression library: " 281228753Smm "It's a bug in liblzma"); 282228753Smm break; 283228753Smm } 284228753Smm return (ARCHIVE_FATAL); 285228753Smm} 286228753Smm 287228753Smm/* 288228753Smm * Setup callback. 289228753Smm */ 290228753Smmstatic int 291231200Smmarchive_compressor_xz_open(struct archive_write_filter *f) 292228753Smm{ 293231200Smm struct private_data *data = f->data; 294228753Smm int ret; 295228753Smm 296231200Smm ret = __archive_write_open_filter(f->next_filter); 297231200Smm if (ret != ARCHIVE_OK) 298231200Smm return (ret); 299228753Smm 300231200Smm if (data->compressed == NULL) { 301238856Smm size_t bs = 65536, bpb; 302238856Smm if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { 303238856Smm /* Buffer size should be a multiple number of the of bytes 304238856Smm * per block for performance. */ 305238856Smm bpb = archive_write_get_bytes_per_block(f->archive); 306238856Smm if (bpb > bs) 307238856Smm bs = bpb; 308238856Smm else if (bpb != 0) 309238856Smm bs -= bs % bpb; 310238856Smm } 311238856Smm data->compressed_buffer_size = bs; 312231200Smm data->compressed 313231200Smm = (unsigned char *)malloc(data->compressed_buffer_size); 314231200Smm if (data->compressed == NULL) { 315231200Smm archive_set_error(f->archive, ENOMEM, 316231200Smm "Can't allocate data for compression buffer"); 317231200Smm return (ARCHIVE_FATAL); 318231200Smm } 319228753Smm } 320228753Smm 321231200Smm f->write = archive_compressor_xz_write; 322228753Smm 323228753Smm /* Initialize compression library. */ 324248616Smm if (f->code == ARCHIVE_FILTER_LZIP) { 325231200Smm const struct option_value *val = 326231200Smm &option_values[data->compression_level]; 327231200Smm 328231200Smm data->lzma_opt.dict_size = val->dict_size; 329231200Smm data->lzma_opt.preset_dict = NULL; 330231200Smm data->lzma_opt.preset_dict_size = 0; 331231200Smm data->lzma_opt.lc = LZMA_LC_DEFAULT; 332231200Smm data->lzma_opt.lp = LZMA_LP_DEFAULT; 333231200Smm data->lzma_opt.pb = LZMA_PB_DEFAULT; 334231200Smm data->lzma_opt.mode = 335231200Smm data->compression_level<= 2? LZMA_MODE_FAST:LZMA_MODE_NORMAL; 336231200Smm data->lzma_opt.nice_len = val->nice_len; 337231200Smm data->lzma_opt.mf = val->mf; 338231200Smm data->lzma_opt.depth = 0; 339231200Smm data->lzmafilters[0].id = LZMA_FILTER_LZMA1; 340231200Smm data->lzmafilters[0].options = &data->lzma_opt; 341231200Smm data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */ 342231200Smm } else { 343231200Smm if (lzma_lzma_preset(&data->lzma_opt, data->compression_level)) { 344231200Smm archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 345231200Smm "Internal error initializing compression library"); 346231200Smm } 347231200Smm data->lzmafilters[0].id = LZMA_FILTER_LZMA2; 348231200Smm data->lzmafilters[0].options = &data->lzma_opt; 349231200Smm data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */ 350228753Smm } 351231200Smm ret = archive_compressor_xz_init_stream(f, data); 352228753Smm if (ret == LZMA_OK) { 353231200Smm f->data = data; 354228753Smm return (0); 355228753Smm } 356228753Smm return (ARCHIVE_FATAL); 357228753Smm} 358228753Smm 359228753Smm/* 360228753Smm * Set write options. 361228753Smm */ 362228753Smmstatic int 363231200Smmarchive_compressor_xz_options(struct archive_write_filter *f, 364231200Smm const char *key, const char *value) 365228753Smm{ 366231200Smm struct private_data *data = (struct private_data *)f->data; 367228753Smm 368228753Smm if (strcmp(key, "compression-level") == 0) { 369228753Smm if (value == NULL || !(value[0] >= '0' && value[0] <= '9') || 370228753Smm value[1] != '\0') 371228753Smm return (ARCHIVE_WARN); 372231200Smm data->compression_level = value[0] - '0'; 373231200Smm if (data->compression_level > 6) 374231200Smm data->compression_level = 6; 375228753Smm return (ARCHIVE_OK); 376228753Smm } 377228753Smm 378232153Smm /* Note: The "warn" return is just to inform the options 379232153Smm * supervisor that we didn't handle it. It will generate 380232153Smm * a suitable error if no one used this option. */ 381228753Smm return (ARCHIVE_WARN); 382228753Smm} 383228753Smm 384228753Smm/* 385228753Smm * Write data to the compressed stream. 386228753Smm */ 387228753Smmstatic int 388231200Smmarchive_compressor_xz_write(struct archive_write_filter *f, 389231200Smm const void *buff, size_t length) 390228753Smm{ 391231200Smm struct private_data *data = (struct private_data *)f->data; 392228753Smm int ret; 393228753Smm 394228753Smm /* Update statistics */ 395231200Smm data->total_in += length; 396248616Smm if (f->code == ARCHIVE_FILTER_LZIP) 397231200Smm data->crc32 = lzma_crc32(buff, length, data->crc32); 398228753Smm 399228753Smm /* Compress input data to output buffer */ 400231200Smm data->stream.next_in = buff; 401231200Smm data->stream.avail_in = length; 402231200Smm if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK) 403228753Smm return (ret); 404228753Smm 405228753Smm return (ARCHIVE_OK); 406228753Smm} 407228753Smm 408228753Smm 409228753Smm/* 410228753Smm * Finish the compression... 411228753Smm */ 412228753Smmstatic int 413231200Smmarchive_compressor_xz_close(struct archive_write_filter *f) 414228753Smm{ 415231200Smm struct private_data *data = (struct private_data *)f->data; 416231200Smm int ret, r1; 417228753Smm 418231200Smm ret = drive_compressor(f, data, 1); 419231200Smm if (ret == ARCHIVE_OK) { 420231200Smm data->total_out += 421231200Smm data->compressed_buffer_size - data->stream.avail_out; 422231200Smm ret = __archive_write_filter(f->next_filter, 423231200Smm data->compressed, 424231200Smm data->compressed_buffer_size - data->stream.avail_out); 425248616Smm if (f->code == ARCHIVE_FILTER_LZIP && ret == ARCHIVE_OK) { 426231200Smm archive_le32enc(data->compressed, data->crc32); 427231200Smm archive_le64enc(data->compressed+4, data->total_in); 428231200Smm archive_le64enc(data->compressed+12, data->total_out + 20); 429231200Smm ret = __archive_write_filter(f->next_filter, 430231200Smm data->compressed, 20); 431228753Smm } 432228753Smm } 433231200Smm lzma_end(&(data->stream)); 434231200Smm r1 = __archive_write_close_filter(f->next_filter); 435231200Smm return (r1 < ret ? r1 : ret); 436228753Smm} 437228753Smm 438231200Smmstatic int 439231200Smmarchive_compressor_xz_free(struct archive_write_filter *f) 440231200Smm{ 441231200Smm struct private_data *data = (struct private_data *)f->data; 442231200Smm free(data->compressed); 443231200Smm free(data); 444231200Smm f->data = NULL; 445231200Smm return (ARCHIVE_OK); 446231200Smm} 447231200Smm 448228753Smm/* 449228753Smm * Utility function to push input data through compressor, 450228753Smm * writing full output blocks as necessary. 451228753Smm * 452228753Smm * Note that this handles both the regular write case (finishing == 453228753Smm * false) and the end-of-archive case (finishing == true). 454228753Smm */ 455228753Smmstatic int 456231200Smmdrive_compressor(struct archive_write_filter *f, 457231200Smm struct private_data *data, int finishing) 458228753Smm{ 459228753Smm int ret; 460228753Smm 461228753Smm for (;;) { 462231200Smm if (data->stream.avail_out == 0) { 463231200Smm data->total_out += data->compressed_buffer_size; 464231200Smm ret = __archive_write_filter(f->next_filter, 465231200Smm data->compressed, 466231200Smm data->compressed_buffer_size); 467231200Smm if (ret != ARCHIVE_OK) 468228753Smm return (ARCHIVE_FATAL); 469231200Smm data->stream.next_out = data->compressed; 470231200Smm data->stream.avail_out = data->compressed_buffer_size; 471228753Smm } 472228753Smm 473228753Smm /* If there's nothing to do, we're done. */ 474231200Smm if (!finishing && data->stream.avail_in == 0) 475228753Smm return (ARCHIVE_OK); 476228753Smm 477231200Smm ret = lzma_code(&(data->stream), 478228753Smm finishing ? LZMA_FINISH : LZMA_RUN ); 479228753Smm 480228753Smm switch (ret) { 481228753Smm case LZMA_OK: 482228753Smm /* In non-finishing case, check if compressor 483228753Smm * consumed everything */ 484231200Smm if (!finishing && data->stream.avail_in == 0) 485228753Smm return (ARCHIVE_OK); 486228753Smm /* In finishing case, this return always means 487228753Smm * there's more work */ 488228753Smm break; 489228753Smm case LZMA_STREAM_END: 490228753Smm /* This return can only occur in finishing case. */ 491228753Smm if (finishing) 492228753Smm return (ARCHIVE_OK); 493231200Smm archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 494228753Smm "lzma compression data error"); 495228753Smm return (ARCHIVE_FATAL); 496228753Smm case LZMA_MEMLIMIT_ERROR: 497231200Smm archive_set_error(f->archive, ENOMEM, 498228753Smm "lzma compression error: " 499228753Smm "%ju MiB would have been needed", 500231200Smm (uintmax_t)((lzma_memusage(&(data->stream)) 501231200Smm + 1024 * 1024 -1) 502228753Smm / (1024 * 1024))); 503228753Smm return (ARCHIVE_FATAL); 504228753Smm default: 505228753Smm /* Any other return value indicates an error. */ 506231200Smm archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 507228753Smm "lzma compression failed:" 508228753Smm " lzma_code() call returned status %d", 509228753Smm ret); 510228753Smm return (ARCHIVE_FATAL); 511228753Smm } 512228753Smm } 513228753Smm} 514228753Smm 515228753Smm#endif /* HAVE_LZMA_H */ 516