[Zrouter-src-freebsd] ZRouter.org: push to FreeBSD HEAD tree
zrouter-src-freebsd at zrouter.org
zrouter-src-freebsd at zrouter.org
Fri Mar 2 15:38:28 UTC 2012
details: http://zrouter.org/hg/FreeBSD/head//rev/f03cc5a9c894
changeset: 364:f03cc5a9c894
user: ray at terran.dlink.ua
date: Fri Mar 02 16:59:15 2012 +0200
description:
Update to FreeBSD-HEAD @232391
diffstat:
head/contrib/libarchive/cpio/test/test_option_0.c | 92 +
head/contrib/libarchive/libarchive/archive_acl.c | 1267 +
head/contrib/libarchive/libarchive/archive_acl_private.h | 87 +
head/contrib/libarchive/libarchive/archive_crypto.c | 1427 +
head/contrib/libarchive/libarchive/archive_crypto_private.h | 376 +
head/contrib/libarchive/libarchive/archive_entry_acl.3 | 233 +
head/contrib/libarchive/libarchive/archive_entry_linkify.3 | 224 +
head/contrib/libarchive/libarchive/archive_entry_locale.h | 88 +
head/contrib/libarchive/libarchive/archive_entry_paths.3 | 151 +
head/contrib/libarchive/libarchive/archive_entry_perms.3 | 207 +
head/contrib/libarchive/libarchive/archive_entry_sparse.c | 156 +
head/contrib/libarchive/libarchive/archive_entry_stat.3 | 272 +
head/contrib/libarchive/libarchive/archive_entry_time.3 | 127 +
head/contrib/libarchive/libarchive/archive_hash.h | 309 -
head/contrib/libarchive/libarchive/archive_options.c | 198 +
head/contrib/libarchive/libarchive/archive_options_private.h | 47 +
head/contrib/libarchive/libarchive/archive_ppmd7.c | 1164 +
head/contrib/libarchive/libarchive/archive_ppmd7_private.h | 119 +
head/contrib/libarchive/libarchive/archive_ppmd_private.h | 158 +
head/contrib/libarchive/libarchive/archive_rb.c | 701 +
head/contrib/libarchive/libarchive/archive_rb.h | 100 +
head/contrib/libarchive/libarchive/archive_read_data.3 | 128 +
head/contrib/libarchive/libarchive/archive_read_disk.c | 198 -
head/contrib/libarchive/libarchive/archive_read_disk_posix.c | 2313 +
head/contrib/libarchive/libarchive/archive_read_extract.3 | 135 +
head/contrib/libarchive/libarchive/archive_read_filter.3 | 127 +
head/contrib/libarchive/libarchive/archive_read_format.3 | 175 +
head/contrib/libarchive/libarchive/archive_read_free.3 | 91 +
head/contrib/libarchive/libarchive/archive_read_header.3 | 89 +
head/contrib/libarchive/libarchive/archive_read_new.3 | 57 +
head/contrib/libarchive/libarchive/archive_read_open.3 | 231 +
head/contrib/libarchive/libarchive/archive_read_set_options.3 | 207 +
head/contrib/libarchive/libarchive/archive_read_set_options.c | 156 +
head/contrib/libarchive/libarchive/archive_read_support_compression_all.c | 60 -
head/contrib/libarchive/libarchive/archive_read_support_compression_bzip2.c | 353 -
head/contrib/libarchive/libarchive/archive_read_support_compression_compress.c | 444 -
head/contrib/libarchive/libarchive/archive_read_support_compression_gzip.c | 465 -
head/contrib/libarchive/libarchive/archive_read_support_compression_none.c | 40 -
head/contrib/libarchive/libarchive/archive_read_support_compression_program.c | 459 -
head/contrib/libarchive/libarchive/archive_read_support_compression_rpm.c | 287 -
head/contrib/libarchive/libarchive/archive_read_support_compression_uu.c | 637 -
head/contrib/libarchive/libarchive/archive_read_support_compression_xz.c | 708 -
head/contrib/libarchive/libarchive/archive_read_support_filter_all.c | 75 +
head/contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c | 370 +
head/contrib/libarchive/libarchive/archive_read_support_filter_compress.c | 454 +
head/contrib/libarchive/libarchive/archive_read_support_filter_gzip.c | 476 +
head/contrib/libarchive/libarchive/archive_read_support_filter_none.c | 52 +
head/contrib/libarchive/libarchive/archive_read_support_filter_program.c | 476 +
head/contrib/libarchive/libarchive/archive_read_support_filter_rpm.c | 288 +
head/contrib/libarchive/libarchive/archive_read_support_filter_uu.c | 680 +
head/contrib/libarchive/libarchive/archive_read_support_filter_xz.c | 985 +
head/contrib/libarchive/libarchive/archive_read_support_format_7zip.c | 3706 +
head/contrib/libarchive/libarchive/archive_read_support_format_by_code.c | 74 +
head/contrib/libarchive/libarchive/archive_read_support_format_cab.c | 3323 +
head/contrib/libarchive/libarchive/archive_read_support_format_lha.c | 2747 +
head/contrib/libarchive/libarchive/archive_read_support_format_rar.c | 2576 +
head/contrib/libarchive/libarchive/archive_string_composition.h | 1351 +
head/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c | 338 +
head/contrib/libarchive/libarchive/archive_write_add_filter_compress.c | 445 +
head/contrib/libarchive/libarchive/archive_write_add_filter_gzip.c | 360 +
head/contrib/libarchive/libarchive/archive_write_add_filter_none.c | 43 +
head/contrib/libarchive/libarchive/archive_write_add_filter_program.c | 327 +
head/contrib/libarchive/libarchive/archive_write_add_filter_xz.c | 505 +
head/contrib/libarchive/libarchive/archive_write_blocksize.3 | 112 +
head/contrib/libarchive/libarchive/archive_write_data.3 | 60 +
head/contrib/libarchive/libarchive/archive_write_disk.c | 2712 -
head/contrib/libarchive/libarchive/archive_write_disk_posix.c | 2856 +
head/contrib/libarchive/libarchive/archive_write_filter.3 | 98 +
head/contrib/libarchive/libarchive/archive_write_finish_entry.3 | 74 +
head/contrib/libarchive/libarchive/archive_write_format.3 | 98 +
head/contrib/libarchive/libarchive/archive_write_free.3 | 81 +
head/contrib/libarchive/libarchive/archive_write_header.3 | 71 +
head/contrib/libarchive/libarchive/archive_write_new.3 | 56 +
head/contrib/libarchive/libarchive/archive_write_open.3 | 233 +
head/contrib/libarchive/libarchive/archive_write_set_compression_bzip2.c | 408 -
head/contrib/libarchive/libarchive/archive_write_set_compression_compress.c | 492 -
head/contrib/libarchive/libarchive/archive_write_set_compression_gzip.c | 477 -
head/contrib/libarchive/libarchive/archive_write_set_compression_none.c | 257 -
head/contrib/libarchive/libarchive/archive_write_set_compression_program.c | 347 -
head/contrib/libarchive/libarchive/archive_write_set_compression_xz.c | 439 -
head/contrib/libarchive/libarchive/archive_write_set_format_7zip.c | 2313 +
head/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c | 761 +
head/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c | 8117 +++
head/contrib/libarchive/libarchive/archive_write_set_format_xar.c | 3182 +
head/contrib/libarchive/libarchive/archive_write_set_options.3 | 437 +
head/contrib/libarchive/libarchive/archive_write_set_options.c | 130 +
head/contrib/libarchive/libarchive/libarchive_changes.3 | 341 +
head/contrib/libarchive/libarchive/test/test_acl_basic.c | 229 -
head/contrib/libarchive/libarchive/test/test_acl_nfs4.c | 291 +
head/contrib/libarchive/libarchive/test/test_acl_pax.tar.uu | 117 +
head/contrib/libarchive/libarchive/test/test_acl_posix1e.c | 277 +
head/contrib/libarchive/libarchive/test/test_archive_clear_error.c | 42 +
head/contrib/libarchive/libarchive/test/test_archive_crypto.c | 145 +
head/contrib/libarchive/libarchive/test/test_archive_read_close_twice.c | 43 +
head/contrib/libarchive/libarchive/test/test_archive_read_close_twice_open_fd.c | 47 +
head/contrib/libarchive/libarchive/test/test_archive_read_close_twice_open_filename.c | 47 +
head/contrib/libarchive/libarchive/test/test_archive_read_next_header_empty.c | 111 +
head/contrib/libarchive/libarchive/test/test_archive_read_next_header_raw.c | 65 +
head/contrib/libarchive/libarchive/test/test_archive_read_open2.c | 109 +
head/contrib/libarchive/libarchive/test/test_archive_read_set_filter_option.c | 55 +
head/contrib/libarchive/libarchive/test/test_archive_read_set_format_option.c | 67 +
head/contrib/libarchive/libarchive/test/test_archive_read_set_option.c | 69 +
head/contrib/libarchive/libarchive/test/test_archive_read_set_options.c | 126 +
head/contrib/libarchive/libarchive/test/test_archive_read_support.c | 98 +
head/contrib/libarchive/libarchive/test/test_archive_set_error.c | 51 +
head/contrib/libarchive/libarchive/test/test_archive_string.c | 344 +
head/contrib/libarchive/libarchive/test/test_archive_string_conversion.c | 629 +
head/contrib/libarchive/libarchive/test/test_archive_string_conversion.txt.Z.uu | 2605 +
head/contrib/libarchive/libarchive/test/test_archive_write_set_filter_option.c | 55 +
head/contrib/libarchive/libarchive/test/test_archive_write_set_format_option.c | 67 +
head/contrib/libarchive/libarchive/test/test_archive_write_set_option.c | 69 +
head/contrib/libarchive/libarchive/test/test_archive_write_set_options.c | 126 +
head/contrib/libarchive/libarchive/test/test_compat_lzip.c | 141 +
head/contrib/libarchive/libarchive/test/test_compat_lzip_1.tlz.uu | 10 +
head/contrib/libarchive/libarchive/test/test_compat_lzip_2.tlz.uu | 9 +
head/contrib/libarchive/libarchive/test/test_compat_mac-1.tar.Z.uu | 38 +
head/contrib/libarchive/libarchive/test/test_compat_mac-2.tar.Z.uu | 19 +
head/contrib/libarchive/libarchive/test/test_compat_mac.c | 212 +
head/contrib/libarchive/libarchive/test/test_compat_pax_libarchive_2x.c | 146 +
head/contrib/libarchive/libarchive/test/test_compat_pax_libarchive_2x.tar.Z.uu | 15 +
head/contrib/libarchive/libarchive/test/test_compat_solaris_pax_sparse.c | 188 +
head/contrib/libarchive/libarchive/test/test_compat_solaris_pax_sparse_1.pax.Z.uu | 53 +
head/contrib/libarchive/libarchive/test/test_compat_solaris_pax_sparse_2.pax.Z.uu | 53 +
head/contrib/libarchive/libarchive/test/test_compat_zip_3.zip.uu | 18 +
head/contrib/libarchive/libarchive/test/test_compat_zip_4.zip.uu | 25 +
head/contrib/libarchive/libarchive/test/test_compat_zip_5.zip.uu | 242 +
head/contrib/libarchive/libarchive/test/test_compat_zip_6.zip.uu | 10 +
head/contrib/libarchive/libarchive/test/test_compat_zip_7.xps.uu | 357 +
head/contrib/libarchive/libarchive/test/test_filter_count.c | 75 +
head/contrib/libarchive/libarchive/test/test_fuzz.cab.uu | 49 +
head/contrib/libarchive/libarchive/test/test_fuzz.lzh.uu | 152 +
head/contrib/libarchive/libarchive/test/test_gnutar_filename_encoding.c | 414 +
head/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c | 1060 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip.c | 703 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj2_bzip2.7z.uu | 319 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj2_copy_1.7z.uu | 614 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj2_copy_2.7z.uu | 615 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj2_copy_lzma.7z.uu | 568 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj2_deflate.7z.uu | 313 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj2_lzma1_1.7z.uu | 287 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj2_lzma1_2.7z.uu | 240 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj2_lzma2_1.7z.uu | 287 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj2_lzma2_2.7z.uu | 240 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj_bzip2.7z.uu | 281 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj_copy.7z.uu | 613 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj_deflate.7z.uu | 275 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj_lzma1.7z.uu | 245 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bcj_lzma2.7z.uu | 245 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_bzip2.7z.uu | 37 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_copy.7z.uu | 7 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_copy_2.7z.uu | 11 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_deflate.7z.uu | 36 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_delta_lzma1.7z.uu | 280 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_delta_lzma2.7z.uu | 280 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_empty_archive.7z.uu | 4 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_empty_file.7z.uu | 5 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_lzma1.7z.uu | 37 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_lzma1_2.7z.uu | 8 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_lzma1_lzma2.7z.uu | 10 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_lzma2.7z.uu | 37 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_ppmd.7z.uu | 235 +
head/contrib/libarchive/libarchive/test/test_read_format_7zip_symbolic_name.7z.uu | 8 +
head/contrib/libarchive/libarchive/test/test_read_format_cab.c | 281 +
head/contrib/libarchive/libarchive/test/test_read_format_cab_1.cab.uu | 9 +
head/contrib/libarchive/libarchive/test/test_read_format_cab_2.cab.uu | 9 +
head/contrib/libarchive/libarchive/test/test_read_format_cab_3.cab.uu | 10 +
head/contrib/libarchive/libarchive/test/test_read_format_cab_filename.c | 164 +
head/contrib/libarchive/libarchive/test/test_read_format_cab_filename_cp932.cab.uu | 7 +
head/contrib/libarchive/libarchive/test/test_read_format_cpio_afio.c | 115 +
head/contrib/libarchive/libarchive/test/test_read_format_cpio_bin_lzip.c | 61 +
head/contrib/libarchive/libarchive/test/test_read_format_cpio_filename.c | 874 +
head/contrib/libarchive/libarchive/test/test_read_format_cpio_filename_cp866.cpio.uu | 15 +
head/contrib/libarchive/libarchive/test/test_read_format_cpio_filename_eucjp.cpio.uu | 15 +
head/contrib/libarchive/libarchive/test/test_read_format_cpio_filename_koi8r.cpio.uu | 15 +
head/contrib/libarchive/libarchive/test/test_read_format_cpio_filename_utf8_jp.cpio.uu | 15 +
head/contrib/libarchive/libarchive/test/test_read_format_cpio_filename_utf8_ru.cpio.uu | 15 +
head/contrib/libarchive/libarchive/test/test_read_format_gtar_filename.c | 512 +
head/contrib/libarchive/libarchive/test/test_read_format_gtar_filename_cp866.tar.Z.uu | 10 +
head/contrib/libarchive/libarchive/test/test_read_format_gtar_filename_eucjp.tar.Z.uu | 10 +
head/contrib/libarchive/libarchive/test/test_read_format_gtar_filename_koi8r.tar.Z.uu | 10 +
head/contrib/libarchive/libarchive/test/test_read_format_iso_joliet_by_nero.iso.Z.uu | 64 +
head/contrib/libarchive/libarchive/test/test_read_format_iso_xorriso.c | 213 +
head/contrib/libarchive/libarchive/test/test_read_format_iso_xorriso.iso.Z.uu | 61 +
head/contrib/libarchive/libarchive/test/test_read_format_isojoliet_versioned.c | 83 +
head/contrib/libarchive/libarchive/test/test_read_format_lha.c | 278 +
head/contrib/libarchive/libarchive/test/test_read_format_lha_filename.c | 218 +
head/contrib/libarchive/libarchive/test/test_read_format_lha_filename_cp932.lzh.uu | 7 +
head/contrib/libarchive/libarchive/test/test_read_format_lha_header0.lzh.uu | 11 +
head/contrib/libarchive/libarchive/test/test_read_format_lha_header1.lzh.uu | 13 +
head/contrib/libarchive/libarchive/test/test_read_format_lha_header2.lzh.uu | 13 +
head/contrib/libarchive/libarchive/test/test_read_format_lha_header3.lzh.uu | 16 +
head/contrib/libarchive/libarchive/test/test_read_format_lha_lh0.lzh.uu | 13 +
head/contrib/libarchive/libarchive/test/test_read_format_lha_lh6.lzh.uu | 13 +
head/contrib/libarchive/libarchive/test/test_read_format_lha_lh7.lzh.uu | 13 +
head/contrib/libarchive/libarchive/test/test_read_format_lha_withjunk.lzh.uu | 13 +
head/contrib/libarchive/libarchive/test/test_read_format_mtree_nomagic.mtree.uu | 11 +
head/contrib/libarchive/libarchive/test/test_read_format_rar.c | 867 +
head/contrib/libarchive/libarchive/test/test_read_format_rar.rar.uu | 11 +
head/contrib/libarchive/libarchive/test/test_read_format_rar_binary_data.rar.uu | 24041 ++++++++++
head/contrib/libarchive/libarchive/test/test_read_format_rar_compress_best.rar.uu | 274 +
head/contrib/libarchive/libarchive/test/test_read_format_rar_compress_normal.rar.uu | 328 +
head/contrib/libarchive/libarchive/test/test_read_format_rar_multi_lzss_blocks.rar.uu | 444 +
head/contrib/libarchive/libarchive/test/test_read_format_rar_noeof.rar.uu | 5 +
head/contrib/libarchive/libarchive/test/test_read_format_rar_ppmd_lzss_conversion.rar.uu | 3930 +
head/contrib/libarchive/libarchive/test/test_read_format_rar_sfx.exe.uu | 2215 +
head/contrib/libarchive/libarchive/test/test_read_format_rar_subblock.rar.uu | 7 +
head/contrib/libarchive/libarchive/test/test_read_format_rar_unicode.rar.uu | 17 +
head/contrib/libarchive/libarchive/test/test_read_format_rar_windows.rar.uu | 22 +
head/contrib/libarchive/libarchive/test/test_read_format_tar_filename.c | 363 +
head/contrib/libarchive/libarchive/test/test_read_format_tar_filename_koi8r.tar.Z.uu | 14 +
head/contrib/libarchive/libarchive/test/test_read_format_ustar_filename.c | 512 +
head/contrib/libarchive/libarchive/test/test_read_format_ustar_filename_cp866.tar.Z.uu | 8 +
head/contrib/libarchive/libarchive/test/test_read_format_ustar_filename_eucjp.tar.Z.uu | 9 +
head/contrib/libarchive/libarchive/test/test_read_format_ustar_filename_koi8r.tar.Z.uu | 8 +
head/contrib/libarchive/libarchive/test/test_read_format_zip_filename.c | 1162 +
head/contrib/libarchive/libarchive/test/test_read_format_zip_filename_cp866.zip.uu | 10 +
head/contrib/libarchive/libarchive/test/test_read_format_zip_filename_cp932.zip.uu | 9 +
head/contrib/libarchive/libarchive/test/test_read_format_zip_filename_koi8r.zip.uu | 10 +
head/contrib/libarchive/libarchive/test/test_read_format_zip_filename_utf8_jp.zip.uu | 15 +
head/contrib/libarchive/libarchive/test/test_read_format_zip_filename_utf8_ru.zip.uu | 11 +
head/contrib/libarchive/libarchive/test/test_read_format_zip_filename_utf8_ru2.zip.uu | 11 +
head/contrib/libarchive/libarchive/test/test_read_format_zip_length_at_end.zip.uu | 8 +
head/contrib/libarchive/libarchive/test/test_read_format_zip_symlink.zip.uu | 10 +
head/contrib/libarchive/libarchive/test/test_read_format_zip_ux.zip.uu | 7 +
head/contrib/libarchive/libarchive/test/test_read_truncated_filter.c | 132 +
head/contrib/libarchive/libarchive/test/test_sparse_basic.c | 464 +
head/contrib/libarchive/libarchive/test/test_ustar_filename_encoding.c | 414 +
head/contrib/libarchive/libarchive/test/test_write_compress_lzip.c | 247 +
head/contrib/libarchive/libarchive/test/test_write_disk_lookup.c | 156 +
head/contrib/libarchive/libarchive/test/test_write_format_7zip.c | 816 +
head/contrib/libarchive/libarchive/test/test_write_format_gnutar.c | 236 +
head/contrib/libarchive/libarchive/test/test_write_format_iso9660.c | 937 +
head/contrib/libarchive/libarchive/test/test_write_format_iso9660_boot.c | 276 +
head/contrib/libarchive/libarchive/test/test_write_format_iso9660_empty.c | 202 +
head/contrib/libarchive/libarchive/test/test_write_format_iso9660_filename.c | 468 +
head/contrib/libarchive/libarchive/test/test_write_format_iso9660_zisofs.c | 819 +
head/contrib/libarchive/libarchive/test/test_write_format_mtree_fflags.c | 134 +
head/contrib/libarchive/libarchive/test/test_write_format_tar_sparse.c | 305 +
head/contrib/libarchive/libarchive/test/test_write_format_xar.c | 312 +
head/contrib/libarchive/libarchive/test/test_write_format_xar_empty.c | 120 +
head/contrib/libarchive/libarchive/test/test_zip_filename_encoding.c | 543 +
head/contrib/libarchive/tar/test/test_option_C_upper.c | 149 +
head/contrib/libarchive/tar/test/test_option_H_upper.c | 92 +
head/contrib/libarchive/tar/test/test_option_L_upper.c | 92 +
head/contrib/libarchive/tar/test/test_option_O_upper.c | 87 +
head/contrib/libarchive/tar/test/test_option_U_upper.c | 159 +
head/contrib/libarchive/tar/test/test_option_X_upper.c | 145 +
head/contrib/libarchive/tar/test/test_option_b.c | 74 +
head/contrib/libarchive/tar/test/test_option_exclude.c | 142 +
head/contrib/libarchive/tar/test/test_option_gid_gname.c | 88 +
head/contrib/libarchive/tar/test/test_option_k.c | 107 +
head/contrib/libarchive/tar/test/test_option_keep_newer_files.c | 56 +
head/contrib/libarchive/tar/test/test_option_keep_newer_files.tar.Z.uu | 7 +
head/contrib/libarchive/tar/test/test_option_n.c | 61 +
head/contrib/libarchive/tar/test/test_option_newer_than.c | 75 +
head/contrib/libarchive/tar/test/test_option_s.tar.Z.uu | 16 +
head/contrib/libarchive/tar/test/test_option_uid_uname.c | 80 +
head/contrib/libarchive/tar/test/test_print_longpath.c | 54 +
head/contrib/libarchive/tar/test/test_print_longpath.tar.Z.uu | 24 +
head/contrib/llvm/tools/bugpoint/BugDriver.cpp | 247 +
head/contrib/llvm/tools/bugpoint/BugDriver.h | 330 +
head/contrib/llvm/tools/bugpoint/CMakeLists.txt | 14 +
head/contrib/llvm/tools/bugpoint/CrashDebugger.cpp | 667 +
head/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp | 516 +
head/contrib/llvm/tools/bugpoint/ExtractFunction.cpp | 370 +
head/contrib/llvm/tools/bugpoint/FindBugs.cpp | 113 +
head/contrib/llvm/tools/bugpoint/ListReducer.h | 201 +
head/contrib/llvm/tools/bugpoint/Makefile | 16 +
head/contrib/llvm/tools/bugpoint/Miscompilation.cpp | 1078 +
head/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp | 265 +
head/contrib/llvm/tools/bugpoint/ToolRunner.cpp | 977 +
head/contrib/llvm/tools/bugpoint/ToolRunner.h | 247 +
head/contrib/llvm/tools/bugpoint/bugpoint.cpp | 209 +
head/contrib/llvm/tools/llc/CMakeLists.txt | 5 +
head/contrib/llvm/tools/llc/Makefile | 21 +
head/contrib/llvm/tools/llc/llc.cpp | 381 +
head/contrib/llvm/tools/lli/CMakeLists.txt | 5 +
head/contrib/llvm/tools/lli/Makefile | 15 +
head/contrib/llvm/tools/lli/lli.cpp | 305 +
head/contrib/llvm/tools/llvm-ar/CMakeLists.txt | 8 +
head/contrib/llvm/tools/llvm-ar/Makefile | 25 +
head/contrib/llvm/tools/llvm-ar/llvm-ar.cpp | 781 +
head/contrib/llvm/tools/llvm-as/CMakeLists.txt | 6 +
head/contrib/llvm/tools/llvm-as/Makefile | 17 +
head/contrib/llvm/tools/llvm-as/llvm-as.cpp | 119 +
head/contrib/llvm/tools/llvm-bcanalyzer/CMakeLists.txt | 6 +
head/contrib/llvm/tools/llvm-bcanalyzer/Makefile | 17 +
head/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp | 629 +
head/contrib/llvm/tools/llvm-diff/CMakeLists.txt | 8 +
head/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp | 209 +
head/contrib/llvm/tools/llvm-diff/DiffConsumer.h | 92 +
head/contrib/llvm/tools/llvm-diff/DiffLog.cpp | 53 +
head/contrib/llvm/tools/llvm-diff/DiffLog.h | 80 +
head/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp | 677 +
head/contrib/llvm/tools/llvm-diff/DifferenceEngine.h | 91 +
head/contrib/llvm/tools/llvm-diff/Makefile | 17 +
head/contrib/llvm/tools/llvm-diff/llvm-diff.cpp | 98 +
head/contrib/llvm/tools/llvm-dis/CMakeLists.txt | 6 +
head/contrib/llvm/tools/llvm-dis/Makefile | 17 +
head/contrib/llvm/tools/llvm-dis/llvm-dis.cpp | 186 +
head/contrib/llvm/tools/llvm-extract/CMakeLists.txt | 5 +
head/contrib/llvm/tools/llvm-extract/Makefile | 18 +
head/contrib/llvm/tools/llvm-extract/llvm-extract.cpp | 238 +
head/contrib/llvm/tools/llvm-ld/CMakeLists.txt | 8 +
head/contrib/llvm/tools/llvm-ld/Makefile | 15 +
head/contrib/llvm/tools/llvm-ld/Optimize.cpp | 130 +
head/contrib/llvm/tools/llvm-ld/llvm-ld.cpp | 732 +
head/contrib/llvm/tools/llvm-link/CMakeLists.txt | 5 +
head/contrib/llvm/tools/llvm-link/Makefile | 17 +
head/contrib/llvm/tools/llvm-link/llvm-link.cpp | 142 +
head/contrib/llvm/tools/llvm-mc/CMakeLists.txt | 6 +
head/contrib/llvm/tools/llvm-mc/Disassembler.cpp | 368 +
head/contrib/llvm/tools/llvm-mc/Disassembler.h | 42 +
head/contrib/llvm/tools/llvm-mc/Makefile | 24 +
head/contrib/llvm/tools/llvm-mc/llvm-mc.cpp | 517 +
head/contrib/llvm/tools/llvm-nm/CMakeLists.txt | 5 +
head/contrib/llvm/tools/llvm-nm/Makefile | 17 +
head/contrib/llvm/tools/llvm-nm/llvm-nm.cpp | 392 +
head/contrib/llvm/tools/llvm-objdump/CMakeLists.txt | 14 +
head/contrib/llvm/tools/llvm-objdump/MCFunction.cpp | 138 +
head/contrib/llvm/tools/llvm-objdump/MCFunction.h | 100 +
head/contrib/llvm/tools/llvm-objdump/MachODump.cpp | 617 +
head/contrib/llvm/tools/llvm-objdump/Makefile | 18 +
head/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp | 459 +
head/contrib/llvm/tools/llvm-objdump/llvm-objdump.h | 46 +
head/contrib/llvm/tools/llvm-prof/CMakeLists.txt | 5 +
head/contrib/llvm/tools/llvm-prof/Makefile | 17 +
head/contrib/llvm/tools/llvm-prof/llvm-prof.cpp | 293 +
head/contrib/llvm/tools/llvm-ranlib/CMakeLists.txt | 6 +
head/contrib/llvm/tools/llvm-ranlib/Makefile | 18 +
head/contrib/llvm/tools/llvm-ranlib/llvm-ranlib.cpp | 101 +
head/contrib/llvm/tools/llvm-rtdyld/CMakeLists.txt | 5 +
head/contrib/llvm/tools/llvm-rtdyld/Makefile | 23 +
head/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp | 151 +
head/contrib/llvm/tools/llvm-stub/CMakeLists.txt | 3 +
head/contrib/llvm/tools/llvm-stub/Makefile | 13 +
head/contrib/llvm/tools/llvm-stub/llvm-stub.c | 77 +
head/contrib/llvm/tools/macho-dump/CMakeLists.txt | 5 +
head/contrib/llvm/tools/macho-dump/Makefile | 23 +
head/contrib/llvm/tools/macho-dump/macho-dump.cpp | 400 +
head/contrib/llvm/tools/opt/AnalysisWrappers.cpp | 94 +
head/contrib/llvm/tools/opt/CMakeLists.txt | 8 +
head/contrib/llvm/tools/opt/GraphPrinters.cpp | 118 +
head/contrib/llvm/tools/opt/Makefile | 14 +
head/contrib/llvm/tools/opt/PrintSCC.cpp | 112 +
head/contrib/llvm/tools/opt/opt.cpp | 713 +
head/contrib/tcsh/nls/Makefile | 24 -
head/contrib/tcsh/nls/Makefile.in | 119 +
head/contrib/tcsh/nls/catgen | 12 +
head/contrib/tcsh/svn | 32 +
350 files changed, 126518 insertions(+), 9345 deletions(-)
diffs (137263 lines):
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/cpio/test/test_option_0.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/cpio/test/test_option_0.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 2003-2010 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+DEFINE_TEST(test_option_0)
+{
+ FILE *filelist;
+ int r;
+
+ assertUmask(0);
+
+ /* Create a few files. */
+ assertMakeFile("file1", 0644, "1234567890");
+ assertMakeFile("file2", 0644, "1234567890");
+ assertMakeFile("file3", 0644, "1234567890");
+ assertMakeFile("file4", 0644, "1234567890");
+
+ /* Create a file list of filenames with varying end-of-line. */
+ filelist = fopen("filelist", "wb");
+ assertEqualInt(fwrite("file1\x0a", 1, 6, filelist), 6);
+ assertEqualInt(fwrite("file2\x0d", 1, 6, filelist), 6);
+ assertEqualInt(fwrite("file3\x0a\x0d", 1, 7, filelist), 7);
+ assertEqualInt(fwrite("file4", 1, 5, filelist), 5);
+ fclose(filelist);
+
+ /* Create a file list of null-delimited names. */
+ filelist = fopen("filelistNull", "wb");
+ assertEqualInt(fwrite("file1\0", 1, 6, filelist), 6);
+ assertEqualInt(fwrite("file2\0", 1, 6, filelist), 6);
+ assertEqualInt(fwrite("file3\0", 1, 6, filelist), 6);
+ assertEqualInt(fwrite("file4", 1, 5, filelist), 5);
+ fclose(filelist);
+
+ assertUmask(022);
+
+ /* Pack up using the file list with text line endings. */
+ r = systemf("%s -o < filelist > archive 2> stderr1.txt", testprog);
+ assertEqualInt(r, 0);
+
+ /* Extract into a new dir. */
+ assertMakeDir("copy", 0775);
+ assertChdir("copy");
+ r = systemf("%s -i < ../archive > stdout3.txt 2> stderr3.txt", testprog);
+ assertEqualInt(r, 0);
+
+ /* Verify the files. */
+ assertIsReg("file1", 0644);
+ assertIsReg("file2", 0644);
+ assertIsReg("file3", 0644);
+ assertIsReg("file4", 0644);
+
+ assertChdir("..");
+
+ /* Pack up using the file list with nulls. */
+ r = systemf("%s -o0 < filelistNull > archiveNull 2> stderr2.txt", testprog);
+ assertEqualInt(r, 0);
+
+ /* Extract into a new dir. */
+ assertMakeDir("copyNull", 0775);
+ assertChdir("copyNull");
+ r = systemf("%s -i < ../archiveNull > stdout4.txt 2> stderr4.txt", testprog);
+ assertEqualInt(r, 0);
+
+ /* Verify the files. */
+ assertIsReg("file1", 0644);
+ assertIsReg("file2", 0644);
+ assertIsReg("file3", 0644);
+ assertIsReg("file4", 0644);
+}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_acl.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_acl.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,1267 @@
+/*-
+ * Copyright (c) 2003-2010 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_WCHAR_H
+#include <wchar.h>
+#endif
+
+#include "archive_acl_private.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+#undef max
+#define max(a, b) ((a)>(b)?(a):(b))
+
+#ifndef HAVE_WMEMCMP
+/* Good enough for simple equality testing, but not for sorting. */
+#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t))
+#endif
+
+static int acl_special(struct archive_acl *acl,
+ int type, int permset, int tag);
+static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl,
+ int type, int permset, int tag, int id);
+static int archive_acl_add_entry_len_l(struct archive_acl *acl,
+ int type, int permset, int tag, int id, const char *name,
+ size_t len, struct archive_string_conv *sc);
+static int isint_w(const wchar_t *start, const wchar_t *end, int *result);
+static int ismode_w(const wchar_t *start, const wchar_t *end, int *result);
+static void next_field_w(const wchar_t **wp, const wchar_t **start,
+ const wchar_t **end, wchar_t *sep);
+static int prefix_w(const wchar_t *start, const wchar_t *end,
+ const wchar_t *test);
+static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
+ const wchar_t *wname, int perm, int id);
+static void append_id_w(wchar_t **wp, int id);
+static int isint(const char *start, const char *end, int *result);
+static int ismode(const char *start, const char *end, int *result);
+static void next_field(const char **p, const char **start,
+ const char **end, char *sep);
+static int prefix_c(const char *start, const char *end,
+ const char *test);
+static void append_entry(char **p, const char *prefix, int tag,
+ const char *name, int perm, int id);
+static void append_id(char **p, int id);
+
+void
+archive_acl_clear(struct archive_acl *acl)
+{
+ struct archive_acl_entry *ap;
+
+ while (acl->acl_head != NULL) {
+ ap = acl->acl_head->next;
+ archive_mstring_clean(&acl->acl_head->name);
+ free(acl->acl_head);
+ acl->acl_head = ap;
+ }
+ if (acl->acl_text_w != NULL) {
+ free(acl->acl_text_w);
+ acl->acl_text_w = NULL;
+ }
+ if (acl->acl_text != NULL) {
+ free(acl->acl_text);
+ acl->acl_text = NULL;
+ }
+ acl->acl_p = NULL;
+ acl->acl_state = 0; /* Not counting. */
+}
+
+void
+archive_acl_copy(struct archive_acl *dest, struct archive_acl *src)
+{
+ struct archive_acl_entry *ap, *ap2;
+
+ archive_acl_clear(dest);
+
+ dest->mode = src->mode;
+ ap = src->acl_head;
+ while (ap != NULL) {
+ ap2 = acl_new_entry(dest,
+ ap->type, ap->permset, ap->tag, ap->id);
+ if (ap2 != NULL)
+ archive_mstring_copy(&ap2->name, &ap->name);
+ ap = ap->next;
+ }
+}
+
+int
+archive_acl_add_entry(struct archive_acl *acl,
+ int type, int permset, int tag, int id, const char *name)
+{
+ struct archive_acl_entry *ap;
+
+ if (acl_special(acl, type, permset, tag) == 0)
+ return ARCHIVE_OK;
+ ap = acl_new_entry(acl, type, permset, tag, id);
+ if (ap == NULL) {
+ /* XXX Error XXX */
+ return ARCHIVE_FAILED;
+ }
+ if (name != NULL && *name != '\0')
+ archive_mstring_copy_mbs(&ap->name, name);
+ else
+ archive_mstring_clean(&ap->name);
+ return ARCHIVE_OK;
+}
+
+int
+archive_acl_add_entry_w_len(struct archive_acl *acl,
+ int type, int permset, int tag, int id, const wchar_t *name, size_t len)
+{
+ struct archive_acl_entry *ap;
+
+ if (acl_special(acl, type, permset, tag) == 0)
+ return ARCHIVE_OK;
+ ap = acl_new_entry(acl, type, permset, tag, id);
+ if (ap == NULL) {
+ /* XXX Error XXX */
+ return ARCHIVE_FAILED;
+ }
+ if (name != NULL && *name != L'\0' && len > 0)
+ archive_mstring_copy_wcs_len(&ap->name, name, len);
+ else
+ archive_mstring_clean(&ap->name);
+ return ARCHIVE_OK;
+}
+
+static int
+archive_acl_add_entry_len_l(struct archive_acl *acl,
+ int type, int permset, int tag, int id, const char *name, size_t len,
+ struct archive_string_conv *sc)
+{
+ struct archive_acl_entry *ap;
+ int r;
+
+ if (acl_special(acl, type, permset, tag) == 0)
+ return ARCHIVE_OK;
+ ap = acl_new_entry(acl, type, permset, tag, id);
+ if (ap == NULL) {
+ /* XXX Error XXX */
+ return ARCHIVE_FAILED;
+ }
+ if (name != NULL && *name != '\0' && len > 0) {
+ r = archive_mstring_copy_mbs_len_l(&ap->name, name, len, sc);
+ } else {
+ r = 0;
+ archive_mstring_clean(&ap->name);
+ }
+ if (r == 0)
+ return (ARCHIVE_OK);
+ else if (errno == ENOMEM)
+ return (ARCHIVE_FATAL);
+ else
+ return (ARCHIVE_WARN);
+}
+
+/*
+ * If this ACL entry is part of the standard POSIX permissions set,
+ * store the permissions in the stat structure and return zero.
+ */
+static int
+acl_special(struct archive_acl *acl, int type, int permset, int tag)
+{
+ if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+ && ((permset & ~007) == 0)) {
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ acl->mode &= ~0700;
+ acl->mode |= (permset & 7) << 6;
+ return (0);
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ acl->mode &= ~0070;
+ acl->mode |= (permset & 7) << 3;
+ return (0);
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ acl->mode &= ~0007;
+ acl->mode |= permset & 7;
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Allocate and populate a new ACL entry with everything but the
+ * name.
+ */
+static struct archive_acl_entry *
+acl_new_entry(struct archive_acl *acl,
+ int type, int permset, int tag, int id)
+{
+ struct archive_acl_entry *ap, *aq;
+
+ /* Type argument must be a valid NFS4 or POSIX.1e type.
+ * The type must agree with anything already set and
+ * the permset must be compatible. */
+ if (type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ return (NULL);
+ }
+ if (permset &
+ ~(ARCHIVE_ENTRY_ACL_PERMS_NFS4
+ | ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4)) {
+ return (NULL);
+ }
+ } else if (type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) {
+ if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) {
+ return (NULL);
+ }
+ if (permset & ~ARCHIVE_ENTRY_ACL_PERMS_POSIX1E) {
+ return (NULL);
+ }
+ } else {
+ return (NULL);
+ }
+
+ /* Verify the tag is valid and compatible with NFS4 or POSIX.1e. */
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_USER:
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ case ARCHIVE_ENTRY_ACL_GROUP:
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ /* Tags valid in both NFS4 and POSIX.1e */
+ break;
+ case ARCHIVE_ENTRY_ACL_MASK:
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ /* Tags valid only in POSIX.1e. */
+ if (type & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) {
+ return (NULL);
+ }
+ break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ /* Tags valid only in NFS4. */
+ if (type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ return (NULL);
+ }
+ break;
+ default:
+ /* No other values are valid. */
+ return (NULL);
+ }
+
+ if (acl->acl_text_w != NULL) {
+ free(acl->acl_text_w);
+ acl->acl_text_w = NULL;
+ }
+ if (acl->acl_text != NULL) {
+ free(acl->acl_text);
+ acl->acl_text = NULL;
+ }
+
+ /* If there's a matching entry already in the list, overwrite it. */
+ ap = acl->acl_head;
+ aq = NULL;
+ while (ap != NULL) {
+ if (ap->type == type && ap->tag == tag && ap->id == id) {
+ ap->permset = permset;
+ return (ap);
+ }
+ aq = ap;
+ ap = ap->next;
+ }
+
+ /* Add a new entry to the end of the list. */
+ ap = (struct archive_acl_entry *)malloc(sizeof(*ap));
+ if (ap == NULL)
+ return (NULL);
+ memset(ap, 0, sizeof(*ap));
+ if (aq == NULL)
+ acl->acl_head = ap;
+ else
+ aq->next = ap;
+ ap->type = type;
+ ap->tag = tag;
+ ap->id = id;
+ ap->permset = permset;
+ acl->acl_types |= type;
+ return (ap);
+}
+
+/*
+ * Return a count of entries matching "want_type".
+ */
+int
+archive_acl_count(struct archive_acl *acl, int want_type)
+{
+ int count;
+ struct archive_acl_entry *ap;
+
+ count = 0;
+ ap = acl->acl_head;
+ while (ap != NULL) {
+ if ((ap->type & want_type) != 0)
+ count++;
+ ap = ap->next;
+ }
+
+ if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0))
+ count += 3;
+ return (count);
+}
+
+/*
+ * Prepare for reading entries from the ACL data. Returns a count
+ * of entries matching "want_type", or zero if there are no
+ * non-extended ACL entries of that type.
+ */
+int
+archive_acl_reset(struct archive_acl *acl, int want_type)
+{
+ int count, cutoff;
+
+ count = archive_acl_count(acl, want_type);
+
+ /*
+ * If the only entries are the three standard ones,
+ * then don't return any ACL data. (In this case,
+ * client can just use chmod(2) to set permissions.)
+ */
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
+ cutoff = 3;
+ else
+ cutoff = 0;
+
+ if (count > cutoff)
+ acl->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ else
+ acl->acl_state = 0;
+ acl->acl_p = acl->acl_head;
+ return (count);
+}
+
+
+/*
+ * Return the next ACL entry in the list. Fake entries for the
+ * standard permissions and include them in the returned list.
+ */
+int
+archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, int *type,
+ int *permset, int *tag, int *id, const char **name)
+{
+ *name = NULL;
+ *id = -1;
+
+ /*
+ * The acl_state is either zero (no entries available), -1
+ * (reading from list), or an entry type (retrieve that type
+ * from ae_stat.aest_mode).
+ */
+ if (acl->acl_state == 0)
+ return (ARCHIVE_WARN);
+
+ /* The first three access entries are special. */
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ switch (acl->acl_state) {
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ *permset = (acl->mode >> 6) & 7;
+ *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ *tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ acl->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ return (ARCHIVE_OK);
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ *permset = (acl->mode >> 3) & 7;
+ *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ acl->acl_state = ARCHIVE_ENTRY_ACL_OTHER;
+ return (ARCHIVE_OK);
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ *permset = acl->mode & 7;
+ *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ *tag = ARCHIVE_ENTRY_ACL_OTHER;
+ acl->acl_state = -1;
+ acl->acl_p = acl->acl_head;
+ return (ARCHIVE_OK);
+ default:
+ break;
+ }
+ }
+
+ while (acl->acl_p != NULL && (acl->acl_p->type & want_type) == 0)
+ acl->acl_p = acl->acl_p->next;
+ if (acl->acl_p == NULL) {
+ acl->acl_state = 0;
+ *type = 0;
+ *permset = 0;
+ *tag = 0;
+ *id = -1;
+ *name = NULL;
+ return (ARCHIVE_EOF); /* End of ACL entries. */
+ }
+ *type = acl->acl_p->type;
+ *permset = acl->acl_p->permset;
+ *tag = acl->acl_p->tag;
+ *id = acl->acl_p->id;
+ if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0)
+ *name = NULL;
+ acl->acl_p = acl->acl_p->next;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Generate a text version of the ACL. The flags parameter controls
+ * the style of the generated ACL.
+ */
+const wchar_t *
+archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
+{
+ int count;
+ size_t length;
+ const wchar_t *wname;
+ const wchar_t *prefix;
+ wchar_t separator;
+ struct archive_acl_entry *ap;
+ int id;
+ wchar_t *wp;
+
+ if (acl->acl_text_w != NULL) {
+ free (acl->acl_text_w);
+ acl->acl_text_w = NULL;
+ }
+
+ separator = L',';
+ count = 0;
+ length = 0;
+ ap = acl->acl_head;
+ while (ap != NULL) {
+ if ((ap->type & flags) != 0) {
+ count++;
+ if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
+ (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
+ length += 8; /* "default:" */
+ length += 5; /* tag name */
+ length += 1; /* colon */
+ if (archive_mstring_get_wcs(a, &ap->name, &wname) == 0 &&
+ wname != NULL)
+ length += wcslen(wname);
+ else
+ length += sizeof(uid_t) * 3 + 1;
+ length ++; /* colon */
+ length += 3; /* rwx */
+ length += 1; /* colon */
+ length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
+ length ++; /* newline */
+ }
+ ap = ap->next;
+ }
+
+ if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
+ length += 10; /* "user::rwx\n" */
+ length += 11; /* "group::rwx\n" */
+ length += 11; /* "other::rwx\n" */
+ }
+
+ if (count == 0)
+ return (NULL);
+
+ /* Now, allocate the string and actually populate it. */
+ wp = acl->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t));
+ if (wp == NULL)
+ __archive_errx(1, "No memory to generate the text version of the ACL");
+ count = 0;
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+ acl->mode & 0700, -1);
+ *wp++ = ',';
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+ acl->mode & 0070, -1);
+ *wp++ = ',';
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+ acl->mode & 0007, -1);
+ count += 3;
+
+ ap = acl->acl_head;
+ while (ap != NULL) {
+ if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 &&
+ archive_mstring_get_wcs(a, &ap->name, &wname) == 0) {
+ *wp++ = separator;
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+ id = ap->id;
+ else
+ id = -1;
+ append_entry_w(&wp, NULL, ap->tag, wname,
+ ap->permset, id);
+ count++;
+ }
+ ap = ap->next;
+ }
+ }
+
+
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
+ prefix = L"default:";
+ else
+ prefix = NULL;
+ ap = acl->acl_head;
+ count = 0;
+ while (ap != NULL) {
+ if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 &&
+ archive_mstring_get_wcs(a, &ap->name, &wname) == 0) {
+ if (count > 0)
+ *wp++ = separator;
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+ id = ap->id;
+ else
+ id = -1;
+ append_entry_w(&wp, prefix, ap->tag,
+ wname, ap->permset, id);
+ count ++;
+ }
+ ap = ap->next;
+ }
+ }
+
+ return (acl->acl_text_w);
+}
+
+
+static void
+append_id_w(wchar_t **wp, int id)
+{
+ if (id < 0)
+ id = 0;
+ if (id > 9)
+ append_id_w(wp, id / 10);
+ *(*wp)++ = L"0123456789"[id % 10];
+}
+
+static void
+append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
+ const wchar_t *wname, int perm, int id)
+{
+ if (prefix != NULL) {
+ wcscpy(*wp, prefix);
+ *wp += wcslen(*wp);
+ }
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ wname = NULL;
+ id = -1;
+ /* FALLTHROUGH */
+ case ARCHIVE_ENTRY_ACL_USER:
+ wcscpy(*wp, L"user");
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ wname = NULL;
+ id = -1;
+ /* FALLTHROUGH */
+ case ARCHIVE_ENTRY_ACL_GROUP:
+ wcscpy(*wp, L"group");
+ break;
+ case ARCHIVE_ENTRY_ACL_MASK:
+ wcscpy(*wp, L"mask");
+ wname = NULL;
+ id = -1;
+ break;
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ wcscpy(*wp, L"other");
+ wname = NULL;
+ id = -1;
+ break;
+ }
+ *wp += wcslen(*wp);
+ *(*wp)++ = L':';
+ if (wname != NULL) {
+ wcscpy(*wp, wname);
+ *wp += wcslen(*wp);
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER
+ || tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ append_id_w(wp, id);
+ id = -1;
+ }
+ *(*wp)++ = L':';
+ *(*wp)++ = (perm & 0444) ? L'r' : L'-';
+ *(*wp)++ = (perm & 0222) ? L'w' : L'-';
+ *(*wp)++ = (perm & 0111) ? L'x' : L'-';
+ if (id != -1) {
+ *(*wp)++ = L':';
+ append_id_w(wp, id);
+ }
+ **wp = L'\0';
+}
+
+int
+archive_acl_text_l(struct archive_acl *acl, int flags,
+ const char **acl_text, size_t *acl_text_len,
+ struct archive_string_conv *sc)
+{
+ int count;
+ size_t length;
+ const char *name;
+ const char *prefix;
+ char separator;
+ struct archive_acl_entry *ap;
+ size_t len;
+ int id, r;
+ char *p;
+
+ if (acl->acl_text != NULL) {
+ free (acl->acl_text);
+ acl->acl_text = NULL;
+ }
+
+ *acl_text = NULL;
+ if (acl_text_len != NULL)
+ *acl_text_len = 0;
+ separator = ',';
+ count = 0;
+ length = 0;
+ ap = acl->acl_head;
+ while (ap != NULL) {
+ if ((ap->type & flags) != 0) {
+ count++;
+ if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
+ (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
+ length += 8; /* "default:" */
+ length += 5; /* tag name */
+ length += 1; /* colon */
+ r = archive_mstring_get_mbs_l(
+ &ap->name, &name, &len, sc);
+ if (r != 0)
+ return (-1);
+ if (len > 0 && name != NULL)
+ length += len;
+ else
+ length += sizeof(uid_t) * 3 + 1;
+ length ++; /* colon */
+ length += 3; /* rwx */
+ length += 1; /* colon */
+ length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
+ length ++; /* newline */
+ }
+ ap = ap->next;
+ }
+
+ if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
+ length += 10; /* "user::rwx\n" */
+ length += 11; /* "group::rwx\n" */
+ length += 11; /* "other::rwx\n" */
+ }
+
+ if (count == 0)
+ return (0);
+
+ /* Now, allocate the string and actually populate it. */
+ p = acl->acl_text = (char *)malloc(length);
+ if (p == NULL)
+ __archive_errx(1, "No memory to generate the text version of the ACL");
+ count = 0;
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+ acl->mode & 0700, -1);
+ *p++ = ',';
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+ acl->mode & 0070, -1);
+ *p++ = ',';
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+ acl->mode & 0007, -1);
+ count += 3;
+
+ for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+ if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) == 0)
+ continue;
+ r = archive_mstring_get_mbs_l(
+ &ap->name, &name, &len, sc);
+ if (r != 0)
+ return (-1);
+ *p++ = separator;
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+ id = ap->id;
+ else
+ id = -1;
+ append_entry(&p, NULL, ap->tag, name,
+ ap->permset, id);
+ count++;
+ }
+ }
+
+
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
+ prefix = "default:";
+ else
+ prefix = NULL;
+ count = 0;
+ for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+ if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) == 0)
+ continue;
+ r = archive_mstring_get_mbs_l(
+ &ap->name, &name, &len, sc);
+ if (r != 0)
+ return (-1);
+ if (count > 0)
+ *p++ = separator;
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+ id = ap->id;
+ else
+ id = -1;
+ append_entry(&p, prefix, ap->tag,
+ name, ap->permset, id);
+ count ++;
+ }
+ }
+
+ *acl_text = acl->acl_text;
+ if (acl_text_len != NULL)
+ *acl_text_len = strlen(acl->acl_text);
+ return (0);
+}
+
+static void
+append_id(char **p, int id)
+{
+ if (id < 0)
+ id = 0;
+ if (id > 9)
+ append_id(p, id / 10);
+ *(*p)++ = "0123456789"[id % 10];
+}
+
+static void
+append_entry(char **p, const char *prefix, int tag,
+ const char *name, int perm, int id)
+{
+ if (prefix != NULL) {
+ strcpy(*p, prefix);
+ *p += strlen(*p);
+ }
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ name = NULL;
+ id = -1;
+ /* FALLTHROUGH */
+ case ARCHIVE_ENTRY_ACL_USER:
+ strcpy(*p, "user");
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ name = NULL;
+ id = -1;
+ /* FALLTHROUGH */
+ case ARCHIVE_ENTRY_ACL_GROUP:
+ strcpy(*p, "group");
+ break;
+ case ARCHIVE_ENTRY_ACL_MASK:
+ strcpy(*p, "mask");
+ name = NULL;
+ id = -1;
+ break;
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ strcpy(*p, "other");
+ name = NULL;
+ id = -1;
+ break;
+ }
+ *p += strlen(*p);
+ *(*p)++ = ':';
+ if (name != NULL) {
+ strcpy(*p, name);
+ *p += strlen(*p);
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER
+ || tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ append_id(p, id);
+ id = -1;
+ }
+ *(*p)++ = ':';
+ *(*p)++ = (perm & 0444) ? 'r' : '-';
+ *(*p)++ = (perm & 0222) ? 'w' : '-';
+ *(*p)++ = (perm & 0111) ? 'x' : '-';
+ if (id != -1) {
+ *(*p)++ = ':';
+ append_id(p, id);
+ }
+ **p = '\0';
+}
+
+/*
+ * Parse a textual ACL. This automatically recognizes and supports
+ * extensions described above. The 'type' argument is used to
+ * indicate the type that should be used for any entries not
+ * explicitly marked as "default:".
+ */
+int
+archive_acl_parse_w(struct archive_acl *acl,
+ const wchar_t *text, int default_type)
+{
+ struct {
+ const wchar_t *start;
+ const wchar_t *end;
+ } field[4], name;
+
+ int fields, n;
+ int type, tag, permset, id;
+ wchar_t sep;
+
+ while (text != NULL && *text != L'\0') {
+ /*
+ * Parse the fields out of the next entry,
+ * advance 'text' to start of next entry.
+ */
+ fields = 0;
+ do {
+ const wchar_t *start, *end;
+ next_field_w(&text, &start, &end, &sep);
+ if (fields < 4) {
+ field[fields].start = start;
+ field[fields].end = end;
+ }
+ ++fields;
+ } while (sep == L':');
+
+ /* Set remaining fields to blank. */
+ for (n = fields; n < 4; ++n)
+ field[n].start = field[n].end = NULL;
+
+ /* Check for a numeric ID in field 1 or 3. */
+ id = -1;
+ isint_w(field[1].start, field[1].end, &id);
+ /* Field 3 is optional. */
+ if (id == -1 && fields > 3)
+ isint_w(field[3].start, field[3].end, &id);
+
+ /*
+ * Solaris extension: "defaultuser::rwx" is the
+ * default ACL corresponding to "user::rwx", etc.
+ */
+ if (field[0].end - field[0].start > 7
+ && wmemcmp(field[0].start, L"default", 7) == 0) {
+ type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+ field[0].start += 7;
+ } else
+ type = default_type;
+
+ name.start = name.end = NULL;
+ if (prefix_w(field[0].start, field[0].end, L"user")) {
+ if (!ismode_w(field[2].start, field[2].end, &permset))
+ return (ARCHIVE_WARN);
+ if (id != -1 || field[1].start < field[1].end) {
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ name = field[1];
+ } else
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ } else if (prefix_w(field[0].start, field[0].end, L"group")) {
+ if (!ismode_w(field[2].start, field[2].end, &permset))
+ return (ARCHIVE_WARN);
+ if (id != -1 || field[1].start < field[1].end) {
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ name = field[1];
+ } else
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ } else if (prefix_w(field[0].start, field[0].end, L"other")) {
+ if (fields == 2
+ && field[1].start < field[1].end
+ && ismode_w(field[1].start, field[1].end, &permset)) {
+ /* This is Solaris-style "other:rwx" */
+ } else if (fields == 3
+ && field[1].start == field[1].end
+ && field[2].start < field[2].end
+ && ismode_w(field[2].start, field[2].end, &permset)) {
+ /* This is FreeBSD-style "other::rwx" */
+ } else
+ return (ARCHIVE_WARN);
+ tag = ARCHIVE_ENTRY_ACL_OTHER;
+ } else if (prefix_w(field[0].start, field[0].end, L"mask")) {
+ if (fields == 2
+ && field[1].start < field[1].end
+ && ismode_w(field[1].start, field[1].end, &permset)) {
+ /* This is Solaris-style "mask:rwx" */
+ } else if (fields == 3
+ && field[1].start == field[1].end
+ && field[2].start < field[2].end
+ && ismode_w(field[2].start, field[2].end, &permset)) {
+ /* This is FreeBSD-style "mask::rwx" */
+ } else
+ return (ARCHIVE_WARN);
+ tag = ARCHIVE_ENTRY_ACL_MASK;
+ } else
+ return (ARCHIVE_WARN);
+
+ /* Add entry to the internal list. */
+ archive_acl_add_entry_w_len(acl, type, permset,
+ tag, id, name.start, name.end - name.start);
+ }
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Parse a string to a positive decimal integer. Returns true if
+ * the string is non-empty and consists only of decimal digits,
+ * false otherwise.
+ */
+static int
+isint_w(const wchar_t *start, const wchar_t *end, int *result)
+{
+ int n = 0;
+ if (start >= end)
+ return (0);
+ while (start < end) {
+ if (*start < '0' || *start > '9')
+ return (0);
+ if (n > (INT_MAX / 10) ||
+ (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {
+ n = INT_MAX;
+ } else {
+ n *= 10;
+ n += *start - '0';
+ }
+ start++;
+ }
+ *result = n;
+ return (1);
+}
+
+/*
+ * Parse a string as a mode field. Returns true if
+ * the string is non-empty and consists only of mode characters,
+ * false otherwise.
+ */
+static int
+ismode_w(const wchar_t *start, const wchar_t *end, int *permset)
+{
+ const wchar_t *p;
+
+ if (start >= end)
+ return (0);
+ p = start;
+ *permset = 0;
+ while (p < end) {
+ switch (*p++) {
+ case 'r': case 'R':
+ *permset |= ARCHIVE_ENTRY_ACL_READ;
+ break;
+ case 'w': case 'W':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE;
+ break;
+ case 'x': case 'X':
+ *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ break;
+ case '-':
+ break;
+ default:
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated
+ * to point to just after the separator. *start points to the first
+ * character of the matched text and *end just after the last
+ * character of the matched identifier. In particular *end - *start
+ * is the length of the field body, not including leading or trailing
+ * whitespace.
+ */
+static void
+next_field_w(const wchar_t **wp, const wchar_t **start,
+ const wchar_t **end, wchar_t *sep)
+{
+ /* Skip leading whitespace to find start of field. */
+ while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') {
+ (*wp)++;
+ }
+ *start = *wp;
+
+ /* Scan for the separator. */
+ while (**wp != L'\0' && **wp != L',' && **wp != L':' &&
+ **wp != L'\n') {
+ (*wp)++;
+ }
+ *sep = **wp;
+
+ /* Trim trailing whitespace to locate end of field. */
+ *end = *wp - 1;
+ while (**end == L' ' || **end == L'\t' || **end == L'\n') {
+ (*end)--;
+ }
+ (*end)++;
+
+ /* Adjust scanner location. */
+ if (**wp != L'\0')
+ (*wp)++;
+}
+
+/*
+ * Return true if the characters [start...end) are a prefix of 'test'.
+ * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
+ */
+static int
+prefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test)
+{
+ if (start == end)
+ return (0);
+
+ if (*start++ != *test++)
+ return (0);
+
+ while (start < end && *start++ == *test++)
+ ;
+
+ if (start < end)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * Parse a textual ACL. This automatically recognizes and supports
+ * extensions described above. The 'type' argument is used to
+ * indicate the type that should be used for any entries not
+ * explicitly marked as "default:".
+ */
+int
+archive_acl_parse_l(struct archive_acl *acl,
+ const char *text, int default_type, struct archive_string_conv *sc)
+{
+ struct {
+ const char *start;
+ const char *end;
+ } field[4], name;
+
+ int fields, n, r, ret = ARCHIVE_OK;
+ int type, tag, permset, id;
+ char sep;
+
+ while (text != NULL && *text != '\0') {
+ /*
+ * Parse the fields out of the next entry,
+ * advance 'text' to start of next entry.
+ */
+ fields = 0;
+ do {
+ const char *start, *end;
+ next_field(&text, &start, &end, &sep);
+ if (fields < 4) {
+ field[fields].start = start;
+ field[fields].end = end;
+ }
+ ++fields;
+ } while (sep == ':');
+
+ /* Set remaining fields to blank. */
+ for (n = fields; n < 4; ++n)
+ field[n].start = field[n].end = NULL;
+
+ /* Check for a numeric ID in field 1 or 3. */
+ id = -1;
+ isint(field[1].start, field[1].end, &id);
+ /* Field 3 is optional. */
+ if (id == -1 && fields > 3)
+ isint(field[3].start, field[3].end, &id);
+
+ /*
+ * Solaris extension: "defaultuser::rwx" is the
+ * default ACL corresponding to "user::rwx", etc.
+ */
+ if (field[0].end - field[0].start > 7
+ && memcmp(field[0].start, "default", 7) == 0) {
+ type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+ field[0].start += 7;
+ } else
+ type = default_type;
+
+ name.start = name.end = NULL;
+ if (prefix_c(field[0].start, field[0].end, "user")) {
+ if (!ismode(field[2].start, field[2].end, &permset))
+ return (ARCHIVE_WARN);
+ if (id != -1 || field[1].start < field[1].end) {
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ name = field[1];
+ } else
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ } else if (prefix_c(field[0].start, field[0].end, "group")) {
+ if (!ismode(field[2].start, field[2].end, &permset))
+ return (ARCHIVE_WARN);
+ if (id != -1 || field[1].start < field[1].end) {
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ name = field[1];
+ } else
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ } else if (prefix_c(field[0].start, field[0].end, "other")) {
+ if (fields == 2
+ && field[1].start < field[1].end
+ && ismode(field[1].start, field[1].end, &permset)) {
+ /* This is Solaris-style "other:rwx" */
+ } else if (fields == 3
+ && field[1].start == field[1].end
+ && field[2].start < field[2].end
+ && ismode(field[2].start, field[2].end, &permset)) {
+ /* This is FreeBSD-style "other::rwx" */
+ } else
+ return (ARCHIVE_WARN);
+ tag = ARCHIVE_ENTRY_ACL_OTHER;
+ } else if (prefix_c(field[0].start, field[0].end, "mask")) {
+ if (fields == 2
+ && field[1].start < field[1].end
+ && ismode(field[1].start, field[1].end, &permset)) {
+ /* This is Solaris-style "mask:rwx" */
+ } else if (fields == 3
+ && field[1].start == field[1].end
+ && field[2].start < field[2].end
+ && ismode(field[2].start, field[2].end, &permset)) {
+ /* This is FreeBSD-style "mask::rwx" */
+ } else
+ return (ARCHIVE_WARN);
+ tag = ARCHIVE_ENTRY_ACL_MASK;
+ } else
+ return (ARCHIVE_WARN);
+
+ /* Add entry to the internal list. */
+ r = archive_acl_add_entry_len_l(acl, type, permset,
+ tag, id, name.start, name.end - name.start, sc);
+ if (r < ARCHIVE_WARN)
+ return (r);
+ if (r != ARCHIVE_OK)
+ ret = ARCHIVE_WARN;
+ }
+ return (ret);
+}
+
+/*
+ * Parse a string to a positive decimal integer. Returns true if
+ * the string is non-empty and consists only of decimal digits,
+ * false otherwise.
+ */
+static int
+isint(const char *start, const char *end, int *result)
+{
+ int n = 0;
+ if (start >= end)
+ return (0);
+ while (start < end) {
+ if (*start < '0' || *start > '9')
+ return (0);
+ if (n > (INT_MAX / 10) ||
+ (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {
+ n = INT_MAX;
+ } else {
+ n *= 10;
+ n += *start - '0';
+ }
+ start++;
+ }
+ *result = n;
+ return (1);
+}
+
+/*
+ * Parse a string as a mode field. Returns true if
+ * the string is non-empty and consists only of mode characters,
+ * false otherwise.
+ */
+static int
+ismode(const char *start, const char *end, int *permset)
+{
+ const char *p;
+
+ if (start >= end)
+ return (0);
+ p = start;
+ *permset = 0;
+ while (p < end) {
+ switch (*p++) {
+ case 'r': case 'R':
+ *permset |= ARCHIVE_ENTRY_ACL_READ;
+ break;
+ case 'w': case 'W':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE;
+ break;
+ case 'x': case 'X':
+ *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ break;
+ case '-':
+ break;
+ default:
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated
+ * to point to just after the separator. *start points to the first
+ * character of the matched text and *end just after the last
+ * character of the matched identifier. In particular *end - *start
+ * is the length of the field body, not including leading or trailing
+ * whitespace.
+ */
+static void
+next_field(const char **p, const char **start,
+ const char **end, char *sep)
+{
+ /* Skip leading whitespace to find start of field. */
+ while (**p == ' ' || **p == '\t' || **p == '\n') {
+ (*p)++;
+ }
+ *start = *p;
+
+ /* Scan for the separator. */
+ while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n') {
+ (*p)++;
+ }
+ *sep = **p;
+
+ /* Trim trailing whitespace to locate end of field. */
+ *end = *p - 1;
+ while (**end == ' ' || **end == '\t' || **end == '\n') {
+ (*end)--;
+ }
+ (*end)++;
+
+ /* Adjust scanner location. */
+ if (**p != '\0')
+ (*p)++;
+}
+
+/*
+ * Return true if the characters [start...end) are a prefix of 'test'.
+ * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
+ */
+static int
+prefix_c(const char *start, const char *end, const char *test)
+{
+ if (start == end)
+ return (0);
+
+ if (*start++ != *test++)
+ return (0);
+
+ while (start < end && *start++ == *test++)
+ ;
+
+ if (start < end)
+ return (0);
+
+ return (1);
+}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_acl_private.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_acl_private.h Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2003-2010 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_ACL_PRIVATE_H_INCLUDED
+#define ARCHIVE_ACL_PRIVATE_H_INCLUDED
+
+#include "archive_string.h"
+
+struct archive_acl_entry {
+ struct archive_acl_entry *next;
+ int type; /* E.g., access or default */
+ int tag; /* E.g., user/group/other/mask */
+ int permset; /* r/w/x bits */
+ int id; /* uid/gid for user/group */
+ struct archive_mstring name; /* uname/gname */
+};
+
+struct archive_acl {
+ mode_t mode;
+ struct archive_acl_entry *acl_head;
+ struct archive_acl_entry *acl_p;
+ int acl_state; /* See acl_next for details. */
+ wchar_t *acl_text_w;
+ char *acl_text;
+ int acl_types;
+};
+
+void archive_acl_clear(struct archive_acl *);
+void archive_acl_copy(struct archive_acl *, struct archive_acl *);
+int archive_acl_count(struct archive_acl *, int);
+int archive_acl_reset(struct archive_acl *, int);
+int archive_acl_next(struct archive *, struct archive_acl *, int,
+ int *, int *, int *, int *, const char **);
+
+int archive_acl_add_entry(struct archive_acl *, int, int, int, int, const char *);
+int archive_acl_add_entry_w_len(struct archive_acl *,
+ int, int, int, int, const wchar_t *, size_t);
+int archive_acl_add_entry_len(struct archive_acl *,
+ int, int, int, int, const char *, size_t);
+
+const wchar_t *archive_acl_text_w(struct archive *, struct archive_acl *, int);
+int archive_acl_text_l(struct archive_acl *, int, const char **, size_t *,
+ struct archive_string_conv *);
+
+/*
+ * Private ACL parser. This is private because it handles some
+ * very weird formats that clients should not be messing with.
+ * Clients should only deal with their platform-native formats.
+ * Because of the need to support many formats cleanly, new arguments
+ * are likely to get added on a regular basis. Clients who try to use
+ * this interface are likely to be surprised when it changes.
+ */
+int archive_acl_parse_w(struct archive_acl *,
+ const wchar_t *, int /* type */);
+int archive_acl_parse_l(struct archive_acl *,
+ const char *, int /* type */,
+ struct archive_string_conv *);
+
+#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_crypto.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_crypto.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,1427 @@
+/*-
+* Copyright (c) 2003-2007 Tim Kientzle
+* Copyright (c) 2011 Andres Mejia
+* Copyright (c) 2011 Michihiro NAKAJIMA
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "archive_platform.h"
+
+#include "archive.h"
+#include "archive_crypto_private.h"
+
+/* In particular, force the configure probe to break if it tries
+ * to test a combination of OpenSSL and libmd. */
+#if defined(ARCHIVE_CRYPTO_OPENSSL) && defined(ARCHIVE_CRYPTO_LIBMD)
+#error Cannot use both OpenSSL and libmd.
+#endif
+
+/*
+ * Message digest functions for Windows platform.
+ */
+#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_WIN)
+
+/*
+ * Initialize a Message digest.
+ */
+static int
+win_crypto_init(Digest_CTX *ctx, ALG_ID algId)
+{
+
+ ctx->valid = 0;
+ if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
+ return (ARCHIVE_FAILED);
+ if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_NEWKEYSET))
+ return (ARCHIVE_FAILED);
+ }
+
+ if (!CryptCreateHash(ctx->cryptProv, algId, 0, 0, &ctx->hash)) {
+ CryptReleaseContext(ctx->cryptProv, 0);
+ return (ARCHIVE_FAILED);
+ }
+
+ ctx->valid = 1;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Update a Message digest.
+ */
+static int
+win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
+{
+
+ if (!ctx->valid)
+ return (ARCHIVE_FAILED);
+
+ CryptHashData(ctx->hash,
+ (unsigned char *)(uintptr_t)buf,
+ (DWORD)len, 0);
+ return (ARCHIVE_OK);
+}
+
+static int
+win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
+{
+ DWORD siglen = bufsize;
+
+ if (!ctx->valid)
+ return (ARCHIVE_FAILED);
+
+ CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0);
+ CryptDestroyHash(ctx->hash);
+ CryptReleaseContext(ctx->cryptProv, 0);
+ ctx->valid = 0;
+ return (ARCHIVE_OK);
+}
+
+#endif /* defined(ARCHIVE_CRYPTO_*_WIN) */
+
+
+/* MD5 implementations */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+
+static int
+__archive_libc_md5init(archive_md5_ctx *ctx)
+{
+ MD5Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ MD5Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_md5final(archive_md5_ctx *ctx, void *md)
+{
+ MD5Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+
+static int
+__archive_libmd_md5init(archive_md5_ctx *ctx)
+{
+ MD5Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ MD5Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_md5final(archive_md5_ctx *ctx, void *md)
+{
+ MD5Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
+
+static int
+__archive_libsystem_md5init(archive_md5_ctx *ctx)
+{
+ CC_MD5_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ CC_MD5_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_md5final(archive_md5_ctx *ctx, void *md)
+{
+ CC_MD5_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+
+static int
+__archive_nettle_md5init(archive_md5_ctx *ctx)
+{
+ md5_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ md5_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_md5final(archive_md5_ctx *ctx, void *md)
+{
+ md5_digest(ctx, MD5_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
+
+static int
+__archive_openssl_md5init(archive_md5_ctx *ctx)
+{
+ EVP_DigestInit(ctx, EVP_md5());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_md5final(archive_md5_ctx *ctx, void *md)
+{
+ /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so
+ * this is meant to cope with that. Real fix is probably to fix
+ * archive_write_set_format_xar.c
+ */
+ if (ctx->digest)
+ EVP_DigestFinal(ctx, md, NULL);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
+
+static int
+__archive_windowsapi_md5init(archive_md5_ctx *ctx)
+{
+ return (win_crypto_init(ctx, CALG_MD5));
+}
+
+static int
+__archive_windowsapi_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_md5final(archive_md5_ctx *ctx, void *md)
+{
+ return (win_crypto_Final(md, 16, ctx));
+}
+
+#else
+
+static int
+__archive_stub_md5init(archive_md5_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_md5final(archive_md5_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* RIPEMD160 implementations */
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+
+static int
+__archive_libc_ripemd160init(archive_rmd160_ctx *ctx)
+{
+ RMD160Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ RMD160Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+ RMD160Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+
+static int
+__archive_libmd_ripemd160init(archive_rmd160_ctx *ctx)
+{
+ RIPEMD160_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ RIPEMD160_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+ RIPEMD160_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+
+static int
+__archive_nettle_ripemd160init(archive_rmd160_ctx *ctx)
+{
+ ripemd160_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ ripemd160_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+ ripemd160_digest(ctx, RIPEMD160_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+
+static int
+__archive_openssl_ripemd160init(archive_rmd160_ctx *ctx)
+{
+ EVP_DigestInit(ctx, EVP_ripemd160());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+ EVP_DigestFinal(ctx, md, NULL);
+ return (ARCHIVE_OK);
+}
+
+#else
+
+static int
+__archive_stub_ripemd160init(archive_rmd160_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA1 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+
+static int
+__archive_libc_sha1init(archive_sha1_ctx *ctx)
+{
+ SHA1Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA1Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ SHA1Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+
+static int
+__archive_libmd_sha1init(archive_sha1_ctx *ctx)
+{
+ SHA1_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA1_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ SHA1_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha1init(archive_sha1_ctx *ctx)
+{
+ CC_SHA1_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ CC_SHA1_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ CC_SHA1_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
+
+static int
+__archive_nettle_sha1init(archive_sha1_ctx *ctx)
+{
+ sha1_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ sha1_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ sha1_digest(ctx, SHA1_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
+
+static int
+__archive_openssl_sha1init(archive_sha1_ctx *ctx)
+{
+ EVP_DigestInit(ctx, EVP_sha1());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so
+ * this is meant to cope with that. Real fix is probably to fix
+ * archive_write_set_format_xar.c
+ */
+ if (ctx->digest)
+ EVP_DigestFinal(ctx, md, NULL);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
+
+static int
+__archive_windowsapi_sha1init(archive_sha1_ctx *ctx)
+{
+ return (win_crypto_init(ctx, CALG_SHA1));
+}
+
+static int
+__archive_windowsapi_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ return (win_crypto_Final(md, 20, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha1init(archive_sha1_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA256 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
+
+static int
+__archive_libc_sha256init(archive_sha256_ctx *ctx)
+{
+ SHA256_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA256_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ SHA256_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
+
+static int
+__archive_libc2_sha256init(archive_sha256_ctx *ctx)
+{
+ SHA256Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA256Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ SHA256Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
+
+static int
+__archive_libc3_sha256init(archive_sha256_ctx *ctx)
+{
+ SHA256Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA256Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ SHA256Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+
+static int
+__archive_libmd_sha256init(archive_sha256_ctx *ctx)
+{
+ SHA256_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA256_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ SHA256_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha256init(archive_sha256_ctx *ctx)
+{
+ CC_SHA256_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ CC_SHA256_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ CC_SHA256_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
+
+static int
+__archive_nettle_sha256init(archive_sha256_ctx *ctx)
+{
+ sha256_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ sha256_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ sha256_digest(ctx, SHA256_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
+
+static int
+__archive_openssl_sha256init(archive_sha256_ctx *ctx)
+{
+ EVP_DigestInit(ctx, EVP_sha256());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ EVP_DigestFinal(ctx, md, NULL);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
+
+static int
+__archive_windowsapi_sha256init(archive_sha256_ctx *ctx)
+{
+ return (win_crypto_init(ctx, CALG_SHA_256));
+}
+
+static int
+__archive_windowsapi_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ return (win_crypto_Final(md, 32, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha256init(archive_sha256_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA384 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
+
+static int
+__archive_libc_sha384init(archive_sha384_ctx *ctx)
+{
+ SHA384_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA384_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ SHA384_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
+
+static int
+__archive_libc2_sha384init(archive_sha384_ctx *ctx)
+{
+ SHA384Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA384Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ SHA384Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
+
+static int
+__archive_libc3_sha384init(archive_sha384_ctx *ctx)
+{
+ SHA384Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA384Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ SHA384Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha384init(archive_sha384_ctx *ctx)
+{
+ CC_SHA384_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ CC_SHA384_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ CC_SHA384_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
+
+static int
+__archive_nettle_sha384init(archive_sha384_ctx *ctx)
+{
+ sha384_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ sha384_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ sha384_digest(ctx, SHA384_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
+
+static int
+__archive_openssl_sha384init(archive_sha384_ctx *ctx)
+{
+ EVP_DigestInit(ctx, EVP_sha384());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ EVP_DigestFinal(ctx, md, NULL);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
+
+static int
+__archive_windowsapi_sha384init(archive_sha384_ctx *ctx)
+{
+ return (win_crypto_init(ctx, CALG_SHA_384));
+}
+
+static int
+__archive_windowsapi_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ return (win_crypto_Final(md, 48, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha384init(archive_sha384_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA512 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
+
+static int
+__archive_libc_sha512init(archive_sha512_ctx *ctx)
+{
+ SHA512_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA512_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ SHA512_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
+
+static int
+__archive_libc2_sha512init(archive_sha512_ctx *ctx)
+{
+ SHA512Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA512Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ SHA512Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+
+static int
+__archive_libc3_sha512init(archive_sha512_ctx *ctx)
+{
+ SHA512Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA512Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ SHA512Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+
+static int
+__archive_libmd_sha512init(archive_sha512_ctx *ctx)
+{
+ SHA512_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA512_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ SHA512_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha512init(archive_sha512_ctx *ctx)
+{
+ CC_SHA512_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ CC_SHA512_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ CC_SHA512_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+
+static int
+__archive_nettle_sha512init(archive_sha512_ctx *ctx)
+{
+ sha512_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ sha512_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ sha512_digest(ctx, SHA512_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+
+static int
+__archive_openssl_sha512init(archive_sha512_ctx *ctx)
+{
+ EVP_DigestInit(ctx, EVP_sha512());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ EVP_DigestFinal(ctx, md, NULL);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
+
+static int
+__archive_windowsapi_sha512init(archive_sha512_ctx *ctx)
+{
+ return (win_crypto_init(ctx, CALG_SHA_512));
+}
+
+static int
+__archive_windowsapi_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ return (win_crypto_Final(md, 64, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha512init(archive_sha512_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* NOTE: Crypto functions are set based on availability and by the following
+ * order of preference.
+ * 1. libc
+ * 2. libc2
+ * 3. libc3
+ * 4. libSystem
+ * 5. OpenSSL
+ * 6. Windows API
+ */
+const struct archive_crypto __archive_crypto =
+{
+/* MD5 */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+ &__archive_libc_md5init,
+ &__archive_libc_md5update,
+ &__archive_libc_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+ &__archive_libmd_md5init,
+ &__archive_libmd_md5update,
+ &__archive_libmd_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
+ &__archive_libsystem_md5init,
+ &__archive_libsystem_md5update,
+ &__archive_libsystem_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+ &__archive_nettle_md5init,
+ &__archive_nettle_md5update,
+ &__archive_nettle_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
+ &__archive_openssl_md5init,
+ &__archive_openssl_md5update,
+ &__archive_openssl_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
+ &__archive_windowsapi_md5init,
+ &__archive_windowsapi_md5update,
+ &__archive_windowsapi_md5final,
+#elif !defined(ARCHIVE_MD5_COMPILE_TEST)
+ &__archive_stub_md5init,
+ &__archive_stub_md5update,
+ &__archive_stub_md5final,
+#endif
+
+/* RIPEMD160 */
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+ &__archive_libc_ripemd160init,
+ &__archive_libc_ripemd160update,
+ &__archive_libc_ripemd160final,
+#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+ &__archive_libmd_ripemd160init,
+ &__archive_libmd_ripemd160update,
+ &__archive_libmd_ripemd160final,
+#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+ &__archive_nettle_ripemd160init,
+ &__archive_nettle_ripemd160update,
+ &__archive_nettle_ripemd160final,
+#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+ &__archive_openssl_ripemd160init,
+ &__archive_openssl_ripemd160update,
+ &__archive_openssl_ripemd160final,
+#elif !defined(ARCHIVE_RMD160_COMPILE_TEST)
+ &__archive_stub_ripemd160init,
+ &__archive_stub_ripemd160update,
+ &__archive_stub_ripemd160final,
+#endif
+
+/* SHA1 */
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+ &__archive_libc_sha1init,
+ &__archive_libc_sha1update,
+ &__archive_libc_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+ &__archive_libmd_sha1init,
+ &__archive_libmd_sha1update,
+ &__archive_libmd_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
+ &__archive_libsystem_sha1init,
+ &__archive_libsystem_sha1update,
+ &__archive_libsystem_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
+ &__archive_nettle_sha1init,
+ &__archive_nettle_sha1update,
+ &__archive_nettle_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
+ &__archive_openssl_sha1init,
+ &__archive_openssl_sha1update,
+ &__archive_openssl_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
+ &__archive_windowsapi_sha1init,
+ &__archive_windowsapi_sha1update,
+ &__archive_windowsapi_sha1final,
+#elif !defined(ARCHIVE_SHA1_COMPILE_TEST)
+ &__archive_stub_sha1init,
+ &__archive_stub_sha1update,
+ &__archive_stub_sha1final,
+#endif
+
+/* SHA256 */
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
+ &__archive_libc_sha256init,
+ &__archive_libc_sha256update,
+ &__archive_libc_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
+ &__archive_libc2_sha256init,
+ &__archive_libc2_sha256update,
+ &__archive_libc2_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
+ &__archive_libc3_sha256init,
+ &__archive_libc3_sha256update,
+ &__archive_libc3_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+ &__archive_libmd_sha256init,
+ &__archive_libmd_sha256update,
+ &__archive_libmd_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
+ &__archive_libsystem_sha256init,
+ &__archive_libsystem_sha256update,
+ &__archive_libsystem_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
+ &__archive_nettle_sha256init,
+ &__archive_nettle_sha256update,
+ &__archive_nettle_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
+ &__archive_openssl_sha256init,
+ &__archive_openssl_sha256update,
+ &__archive_openssl_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
+ &__archive_windowsapi_sha256init,
+ &__archive_windowsapi_sha256update,
+ &__archive_windowsapi_sha256final,
+#elif !defined(ARCHIVE_SHA256_COMPILE_TEST)
+ &__archive_stub_sha256init,
+ &__archive_stub_sha256update,
+ &__archive_stub_sha256final,
+#endif
+
+/* SHA384 */
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
+ &__archive_libc_sha384init,
+ &__archive_libc_sha384update,
+ &__archive_libc_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
+ &__archive_libc2_sha384init,
+ &__archive_libc2_sha384update,
+ &__archive_libc2_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
+ &__archive_libc3_sha384init,
+ &__archive_libc3_sha384update,
+ &__archive_libc3_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
+ &__archive_libsystem_sha384init,
+ &__archive_libsystem_sha384update,
+ &__archive_libsystem_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
+ &__archive_nettle_sha384init,
+ &__archive_nettle_sha384update,
+ &__archive_nettle_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
+ &__archive_openssl_sha384init,
+ &__archive_openssl_sha384update,
+ &__archive_openssl_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
+ &__archive_windowsapi_sha384init,
+ &__archive_windowsapi_sha384update,
+ &__archive_windowsapi_sha384final,
+#elif !defined(ARCHIVE_SHA384_COMPILE_TEST)
+ &__archive_stub_sha384init,
+ &__archive_stub_sha384update,
+ &__archive_stub_sha384final,
+#endif
+
+/* SHA512 */
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
+ &__archive_libc_sha512init,
+ &__archive_libc_sha512update,
+ &__archive_libc_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
+ &__archive_libc2_sha512init,
+ &__archive_libc2_sha512update,
+ &__archive_libc2_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+ &__archive_libc3_sha512init,
+ &__archive_libc3_sha512update,
+ &__archive_libc3_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+ &__archive_libmd_sha512init,
+ &__archive_libmd_sha512update,
+ &__archive_libmd_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+ &__archive_libsystem_sha512init,
+ &__archive_libsystem_sha512update,
+ &__archive_libsystem_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+ &__archive_nettle_sha512init,
+ &__archive_nettle_sha512update,
+ &__archive_nettle_sha512final,
+#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+ &__archive_openssl_sha512init,
+ &__archive_openssl_sha512update,
+ &__archive_openssl_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
+ &__archive_windowsapi_sha512init,
+ &__archive_windowsapi_sha512update,
+ &__archive_windowsapi_sha512final
+#elif !defined(ARCHIVE_SHA512_COMPILE_TEST)
+ &__archive_stub_sha512init,
+ &__archive_stub_sha512update,
+ &__archive_stub_sha512final
+#endif
+};
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_crypto_private.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_crypto_private.h Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,376 @@
+/*-
+* Copyright (c) 2003-2007 Tim Kientzle
+* Copyright (c) 2011 Andres Mejia
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
+#define ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
+
+/*
+ * Crypto support in various Operating Systems:
+ *
+ * NetBSD:
+ * - MD5 and SHA1 in libc: without _ after algorithm name
+ * - SHA2 in libc: with _ after algorithm name
+ *
+ * OpenBSD:
+ * - MD5, SHA1 and SHA2 in libc: without _ after algorithm name
+ * - OpenBSD 4.4 and earlier have SHA2 in libc with _ after algorithm name
+ *
+ * DragonFly and FreeBSD:
+ * - MD5 libmd: without _ after algorithm name
+ * - SHA1, SHA256 and SHA512 in libmd: with _ after algorithm name
+ *
+ * Mac OS X (10.4 and later):
+ * - MD5, SHA1 and SHA2 in libSystem: with CC_ prefix and _ after algorithm name
+ *
+ * OpenSSL:
+ * - MD5, SHA1 and SHA2 in libcrypto: with _ after algorithm name
+ *
+ * Windows:
+ * - MD5, SHA1 and SHA2 in archive_crypto.c using Windows crypto API
+ */
+
+/* libc crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+#include <md5.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+#include <rmd160.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+#include <sha1.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+#include <sha2.h>
+#endif
+
+/* libmd crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_RMD160_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+#define ARCHIVE_CRYPTO_LIBMD 1
+#endif
+
+#if defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+#include <md5.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+#include <ripemd.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+#include <sha.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+#include <sha256.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+#include <sha512.h>
+#endif
+
+/* libSystem crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+#include <CommonCrypto/CommonDigest.h>
+#endif
+
+/* Nettle crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+#include <nettle/md5.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+#include <nettle/ripemd160.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+#include <nettle/sha.h>
+#endif
+
+/* OpenSSL crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_RMD160_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+#define ARCHIVE_CRYPTO_OPENSSL 1
+#include <openssl/evp.h>
+#endif
+
+/* Windows crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_WIN)
+#include <wincrypt.h>
+typedef struct {
+ int valid;
+ HCRYPTPROV cryptProv;
+ HCRYPTHASH hash;
+} Digest_CTX;
+#endif
+
+/* typedefs */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+typedef MD5_CTX archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+typedef MD5_CTX archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
+typedef CC_MD5_CTX archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+typedef struct md5_ctx archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
+typedef EVP_MD_CTX archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
+typedef Digest_CTX archive_md5_ctx;
+#else
+typedef unsigned char archive_md5_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+typedef RMD160_CTX archive_rmd160_ctx;
+#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+typedef RIPEMD160_CTX archive_rmd160_ctx;
+#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+typedef struct ripemd160_ctx archive_rmd160_ctx;
+#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+typedef EVP_MD_CTX archive_rmd160_ctx;
+#else
+typedef unsigned char archive_rmd160_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+typedef SHA1_CTX archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+typedef SHA1_CTX archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
+typedef CC_SHA1_CTX archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
+typedef struct sha1_ctx archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
+typedef EVP_MD_CTX archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
+typedef Digest_CTX archive_sha1_ctx;
+#else
+typedef unsigned char archive_sha1_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
+typedef SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
+typedef SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
+typedef SHA2_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+typedef SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
+typedef CC_SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
+typedef struct sha256_ctx archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
+typedef EVP_MD_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
+typedef Digest_CTX archive_sha256_ctx;
+#else
+typedef unsigned char archive_sha256_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
+typedef SHA384_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
+typedef SHA384_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
+typedef SHA2_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
+typedef CC_SHA512_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
+typedef struct sha384_ctx archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
+typedef EVP_MD_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
+typedef Digest_CTX archive_sha384_ctx;
+#else
+typedef unsigned char archive_sha384_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
+typedef SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
+typedef SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+typedef SHA2_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+typedef SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+typedef CC_SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+typedef struct sha512_ctx archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+typedef EVP_MD_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
+typedef Digest_CTX archive_sha512_ctx;
+#else
+typedef unsigned char archive_sha512_ctx;
+#endif
+
+/* defines */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_MD5_LIBMD) || \
+ defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_MD5_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_MD5_WIN)
+#define ARCHIVE_HAS_MD5
+#endif
+#define archive_md5_init(ctx)\
+ __archive_crypto.md5init(ctx)
+#define archive_md5_final(ctx, md)\
+ __archive_crypto.md5final(ctx, md)
+#define archive_md5_update(ctx, buf, n)\
+ __archive_crypto.md5update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_RMD160_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+#define ARCHIVE_HAS_RMD160
+#endif
+#define archive_rmd160_init(ctx)\
+ __archive_crypto.rmd160init(ctx)
+#define archive_rmd160_final(ctx, md)\
+ __archive_crypto.rmd160final(ctx, md)
+#define archive_rmd160_update(ctx, buf, n)\
+ __archive_crypto.rmd160update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_LIBMD) || \
+ defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_WIN)
+#define ARCHIVE_HAS_SHA1
+#endif
+#define archive_sha1_init(ctx)\
+ __archive_crypto.sha1init(ctx)
+#define archive_sha1_final(ctx, md)\
+ __archive_crypto.sha1final(ctx, md)
+#define archive_sha1_update(ctx, buf, n)\
+ __archive_crypto.sha1update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_WIN)
+#define ARCHIVE_HAS_SHA256
+#endif
+#define archive_sha256_init(ctx)\
+ __archive_crypto.sha256init(ctx)
+#define archive_sha256_final(ctx, md)\
+ __archive_crypto.sha256final(ctx, md)
+#define archive_sha256_update(ctx, buf, n)\
+ __archive_crypto.sha256update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_WIN)
+#define ARCHIVE_HAS_SHA384
+#endif
+#define archive_sha384_init(ctx)\
+ __archive_crypto.sha384init(ctx)
+#define archive_sha384_final(ctx, md)\
+ __archive_crypto.sha384final(ctx, md)
+#define archive_sha384_update(ctx, buf, n)\
+ __archive_crypto.sha384update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBC3) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_WIN)
+#define ARCHIVE_HAS_SHA512
+#endif
+#define archive_sha512_init(ctx)\
+ __archive_crypto.sha512init(ctx)
+#define archive_sha512_final(ctx, md)\
+ __archive_crypto.sha512final(ctx, md)
+#define archive_sha512_update(ctx, buf, n)\
+ __archive_crypto.sha512update(ctx, buf, n)
+
+/* Minimal interface to crypto functionality for internal use in libarchive */
+struct archive_crypto
+{
+ /* Message Digest */
+ int (*md5init)(archive_md5_ctx *ctx);
+ int (*md5update)(archive_md5_ctx *, const void *, size_t);
+ int (*md5final)(archive_md5_ctx *, void *);
+ int (*rmd160init)(archive_rmd160_ctx *);
+ int (*rmd160update)(archive_rmd160_ctx *, const void *, size_t);
+ int (*rmd160final)(archive_rmd160_ctx *, void *);
+ int (*sha1init)(archive_sha1_ctx *);
+ int (*sha1update)(archive_sha1_ctx *, const void *, size_t);
+ int (*sha1final)(archive_sha1_ctx *, void *);
+ int (*sha256init)(archive_sha256_ctx *);
+ int (*sha256update)(archive_sha256_ctx *, const void *, size_t);
+ int (*sha256final)(archive_sha256_ctx *, void *);
+ int (*sha384init)(archive_sha384_ctx *);
+ int (*sha384update)(archive_sha384_ctx *, const void *, size_t);
+ int (*sha384final)(archive_sha384_ctx *, void *);
+ int (*sha512init)(archive_sha512_ctx *);
+ int (*sha512update)(archive_sha512_ctx *, const void *, size_t);
+ int (*sha512final)(archive_sha512_ctx *, void *);
+};
+
+extern const struct archive_crypto __archive_crypto;
+
+#endif
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_entry_acl.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_entry_acl.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,233 @@
+.\" Copyright (c) 2010 Joerg Sonnenberger
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd February 21, 2010
+.Dt ARCHIVE_ENTRY_ACL 3
+.Os
+.Sh NAME
+.Nm archive_entry_acl_add_entry ,
+.Nm archive_entry_acl_add_entry_w ,
+.Nm archive_entry_acl_clear ,
+.Nm archive_entry_acl_count ,
+.Nm archive_entry_acl_next ,
+.Nm archive_entry_acl_next_w ,
+.Nm archive_entry_acl_reset ,
+.Nm archive_entry_acl_text_w
+.Nd functions for manipulating Access Control Lists in archive entry descriptions
+.Sh SYNOPSIS
+.In archive_entry.h
+.Ft void
+.Fo archive_entry_acl_add_entry
+.Fa "struct archive_entry *a"
+.Fa "int type"
+.Fa "int permset"
+.Fa "int tag"
+.Fa "int qualifier"
+.Fa "const char *name"
+.Fc
+.Ft void
+.Fo archive_entry_acl_add_entry_w
+.Fa "struct archive_entry *a"
+.Fa "int type"
+.Fa "int permset"
+.Fa "int tag"
+.Fa "int qualifier"
+.Fa "const wchar_t *name"
+.Fc
+.Ft void
+.Fn archive_entry_acl_clear "struct archive_entry *a"
+.Ft int
+.Fn archive_entry_acl_count "struct archive_entry *a" "int type"
+.Ft int
+.Fo archive_entry_acl_next
+.Fa "struct archive_entry *a"
+.Fa "int type"
+.Fa "int *ret_type"
+.Fa "int *ret_permset"
+.Fa "int *ret_tag"
+.Fa "int *ret_qual"
+.Fa "const char **ret_name"
+.Fc
+.Ft int
+.Fo archive_entry_acl_next_w
+.Fa "struct archive_entry *a"
+.Fa "int type"
+.Fa "int *ret_type"
+.Fa "int *ret_permset"
+.Fa "int *ret_tag"
+.Fa "int *ret_qual"
+.Fa "const wchar_t **ret_name"
+.Fc
+.Ft int
+.Fn archive_entry_acl_reset "struct archive_entry *a" "int type"
+.Ft const wchar_t *
+.Fn archive_entry_acl_text_w "struct archive_entry *a" "int flags"
+.\" enum?
+.Sh DESCRIPTION
+An
+.Dq Access Control List
+is a generalisation of the classic Unix permission system.
+The ACL interface of
+.Nm libarchive
+is derived from the POSIX.1e draft, but restricted to simplify dealing
+with practical implementations in various Operating Systems and archive formats.
+.Pp
+An ACL consists of a number of independent entries.
+Each entry specifies the permission set as bitmask of basic permissions.
+Valid permissions are:
+.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_EXECUTE"
+.It Dv ARCHIVE_ENTRY_ACL_EXECUTE
+.It Dv ARCHIVE_ENTRY_ACL_WRITE
+.It Dv ARCHIVE_ENTRY_ACL_READ
+.El
+The permissions correspond to the normal Unix permissions.
+.Pp
+The tag specifies the principal to which the permission applies.
+Valid values are:
+.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ"
+.It Dv ARCHIVE_ENTRY_ACL_USER
+The user specified by the name field.
+.It Dv ARCHIVE_ENTRY_ACL_USER_OBJ
+The owner of the file.
+.It Dv ARCHIVE_ENTRY_ACL_GROUP
+The group specied by the name field.
+.It Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
+The group who owns the file.
+.It Dv ARCHIVE_ENTRY_ACL_MASK
+The maximum permissions to be obtained via group permissions.
+.It Dv ARCHIVE_ENTRY_ACL_OTHER
+Any principal who doesn't have a user or group entry.
+.El
+The principals
+.Dv ARCHIVE_ENTRY_ACL_USER_OBJ ,
+.Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
+and
+.Dv ARCHIVE_ENTRY_ACL_OTHER
+are equivalent to user, group and other in the classic Unix permission
+model and specify non-extended ACL entries.
+.Pp
+All files have an access ACL
+.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS .
+This specifies the permissions required for access to the file itself.
+Directories have an additional ACL
+.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT ,
+which controls the initial access ACL for newly created directory entries.
+.Pp
+.Fn archive_entry_acl_add_entry
+and
+.Fn archive_entry_acl_add_entry_w
+add a single ACL entry.
+For the access ACL and non-extended principals, the classic Unix permissions
+are updated.
+.Pp
+.Fn archive_entry_acl_clear
+removes all ACL entries and resets the enumeration pointer.
+.Pp
+.Fn archive_entry_acl_count
+counts the ACL entries that have the given type mask.
+.Fa type
+can be the bitwise-or of
+.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+and
+.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT .
+If
+.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+is included and at least one extended ACL entry is found,
+the three non-extened ACLs are added.
+.Pp
+.Fn archive_entry_acl_next
+and
+.Fn archive_entry_acl_next_w
+return the next entry of the ACL list.
+This functions may only be called after
+.Fn archive_entry_acl_reset
+has indicated the presence of extended ACL entries.
+.Pp
+.Fn archive_entry_acl_reset
+prepare reading the list of ACL entries with
+.Fn archive_entry_acl_next
+or
+.Fn archive_entry_acl_next_w .
+The function returns either 0, if no non-extended ACLs are found.
+In this case, the access permissions should be obtained by
+.Xr archive_entry_mode 3
+or set using
+.Xr chmod 2 .
+Otherwise, the function returns the same value as
+.Fn archive_entry_acl_count .
+.Pp
+.Fn archive_entry_acl_text_w
+converts the ACL entries for the given type mask into a wide string.
+In addition to the normal type flags,
+.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
+and
+.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
+can be specified to further customize the result.
+The returned long string is valid until the next call to
+.Fn archive_entry_acl_clear ,
+.Fn archive_entry_acl_add_entry ,
+.Fn archive_entry_acl_add_entry_w
+or
+.Fn archive_entry_acl_text_w .
+.Sh RETURN VALUES
+.Fn archive_entry_acl_count
+and
+.Fn archive_entry_acl_reset
+returns the number of ACL entries that match the given type mask.
+If the type mask includes
+.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+and at least one extended ACL entry exists, the three classic Unix
+permissions are counted.
+.Pp
+.Fn archive_entry_acl_next
+and
+.Fn archive_entry_acl_next_w
+return
+.Dv ARCHIVE_OK
+on success,
+.Dv ARCHIVE_EOF
+if no more ACL entries exist
+and
+.Dv ARCHIVE_WARN
+if
+.Fn archive_entry_acl_reset
+has not been called first.
+.Pp
+.Fn archive_entry_text_w
+returns a wide string representation of the ACL entrise matching the
+given type mask.
+The returned long string is valid until the next call to
+.Fn archive_entry_acl_clear ,
+.Fn archive_entry_acl_add_entry ,
+.Fn archive_entry_acl_add_entry_w
+or
+.Fn archive_entry_acl_text_w .
+.Sh SEE ALSO
+.Xr archive 3 ,
+.Xr archive_entry 3
+.Sh BUGS
+.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
+and
+.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
+are not documented.
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_entry_linkify.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_entry_linkify.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,224 @@
+.\" Copyright (c) 2010 Joerg Sonnenberger
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd February 20, 2010
+.Dt ARCHIVE_ENTRY_LINKIFY 3
+.Os
+.Sh NAME
+.Nm archive_entry_linkresolver ,
+.Nm archive_entry_linkresolver_new ,
+.Nm archive_entry_linkresolver_set_strategy ,
+.Nm archive_entry_linkresolver_free ,
+.Nm archive_entry_linkify
+.Nd hardlink resolver functions
+.Sh LIBRARY
+.Lb libarchive
+.Sh SYNOPSIS
+.In archive_entry.h
+.Ft struct archive_entry_linkresolver *
+.Fn archive_entry_linkresolver_new void
+.Ft void
+.Fo archive_entry_linkresolver_set_strategy
+.Fa "struct archive_entry_linkresolver *resolver"
+.Fa "int format"
+.Fc
+.Ft void
+.Fo archive_entry_linkresolver_free
+.Fa "struct archive_entry_linkresolver *resolver"
+.Fc
+.Ft void
+.Fo archive_entry_linkify
+.Fa "struct archive_entry_linkresolver *resolver"
+.Fa "struct archive_entry **entry"
+.Fa "struct archive_entry **sparse"
+.Fc
+.Sh DESCRIPTION
+Programs that want to create archives have to deal with hardlinks.
+Hardlinks are handled in different ways by the archive formats.
+The basic strategies are:
+.Bl -enum
+.It
+Ignore hardlinks and store the body for each reference (old cpio, zip).
+.It
+Store the body the first time an inode is seen (ustar, pax).
+.It
+Store the body the last time an inode is seen (new cpio).
+.El
+.Pp
+The
+.Nm
+functions help by providing a unified interface and handling the complexity
+behind the scene.
+.Pp
+The
+.Nm
+functions assume that
+.Vt archive_entry
+instances have valid nlinks, inode and device values.
+The inode and device value is used to match entries.
+The nlinks value is used to determined if all references have been found and
+if the internal references can be recycled.
+.Pp
+The
+.Fn archive_entry_linkresolver_new
+function allocates a new link resolver.
+The instance can be freed using
+.Fn archive_entry_linkresolver_free .
+All deferred entries are flushed and the internal storage is freed.
+.Pp
+The
+.Fn archive_entry_linkresolver_set_strategy
+function selects the optimal hardlink strategy for the given format.
+The format code can be obtained from
+.Xr archive_format 3 .
+The function can be called more than once, but it is recommended to
+flush all deferred entries first.
+.Pp
+The
+.Fn archive_entry_linkify
+function is the core of
+.Nm .
+The
+.Fn entry
+argument points to the
+.Vt archive_entry
+that should be written.
+Depending on the strategy one of the following actions is taken:
+.Bl -enum
+.It
+For the simple archive formats
+.Va *entry
+is left unmodified and
+.Va *sparse
+is set to
+.Dv NULL .
+.It
+For tar like archive formats,
+.Va *sparse
+is set to
+.Dv NULL .
+If
+.Va *entry
+is
+.Dv NULL ,
+no action is taken.
+If the hardlink count of
+.Va *entry
+is larger than 1 and the file type is a regular file or symbolic link,
+the internal list is searched for a matching inode.
+If such an inode is found, the link count is decremented and the file size
+of
+.Va *entry
+is set to 0 to notify that no body should be written.
+If no such inode is found, a copy of the entry is added to the internal cache
+with a link count reduced by one.
+.It
+For new cpio like archive formats a value for
+.Va *entry
+of
+.Dv NULL
+is used to flush deferred entries.
+In that case
+.Va *entry
+is set to an arbitrary deferred entry and the entry itself is removed from the
+internal list.
+If the internal list is empty,
+.Va *entry
+is set to
+.Dv NULL .
+In either case,
+.Va *sparse
+is set to
+.Dv NULL
+and the function returns.
+If the hardlink count of
+.Va *entry
+is one or the file type is a directory or device,
+.Va *sparse
+is set to
+.Dv NULL
+and no further action is taken.
+Otherwise, the internal list is searched for a matching inode.
+If such an inode is not found, the entry is added to the internal list,
+both
+.Va *entry
+and
+.Va *sparse
+are set to
+.Dv NULL
+and the function returns.
+If such an inode is found, the link count is decremented.
+If it remains larger than one, the existing entry on the internal list
+is swapped with
+.Va *entry
+after retaining the link count.
+The existing entry is returned in
+.Va *entry .
+If the link count reached one, the new entry is also removed from the
+internal list and returned in
+.Va *sparse .
+Otherwise
+.Va *sparse
+is set to
+.Dv NULL .
+.El
+.Pp
+The general usage is therefore:
+.Bl -enum
+.It
+For each new archive entry, call
+.Fn archive_entry_linkify .
+.It
+Keep in mind that the entries returned may have a size of 0 now.
+.It
+If
+.Va *entry
+is not
+.Dv NULL ,
+archive it.
+.It
+If
+.Va *sparse
+is not
+.Dv NULL ,
+archive it.
+.It
+After all entries have been written to disk, call
+.Fn archive_entry_linkify
+with
+.Va *entry
+set to
+.Dv NULL
+and archive the returned entry as long as it is not
+.Dv NULL .
+.El
+.Sh RETURN VALUES
+.Fn archive_entry_linkresolver_new
+returns
+.Dv NULL
+on
+.Xr malloc 3
+failures.
+.Sh SEE ALSO
+.Xr archive_entry 3
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_entry_locale.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_entry_locale.h Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2011 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_ENTRY_LOCALE_H_INCLUDED
+#define ARCHIVE_ENTRY_LOCALE_H_INCLUDED
+
+struct archive_entry;
+struct archive_string_conv;
+
+/*
+ * Utility functions to set and get entry attributes by translating
+ * character-set. These are designed for use in format readers and writers.
+ *
+ * The return code and interface of these are quite different from other
+ * functions for archive_entry defined in archive_entry.h.
+ * Common return code are:
+ * Return 0 if the string conversion succeeded.
+ * Return -1 if the string conversion failed.
+ */
+
+#define archive_entry_gname_l _archive_entry_gname_l
+int _archive_entry_gname_l(struct archive_entry *,
+ const char **, size_t *, struct archive_string_conv *);
+#define archive_entry_hardlink_l _archive_entry_hardlink_l
+int _archive_entry_hardlink_l(struct archive_entry *,
+ const char **, size_t *, struct archive_string_conv *);
+#define archive_entry_pathname_l _archive_entry_pathname_l
+int _archive_entry_pathname_l(struct archive_entry *,
+ const char **, size_t *, struct archive_string_conv *);
+#define archive_entry_symlink_l _archive_entry_symlink_l
+int _archive_entry_symlink_l(struct archive_entry *,
+ const char **, size_t *, struct archive_string_conv *);
+#define archive_entry_uname_l _archive_entry_uname_l
+int _archive_entry_uname_l(struct archive_entry *,
+ const char **, size_t *, struct archive_string_conv *);
+#define archive_entry_acl_text_l _archive_entry_acl_text_l
+int _archive_entry_acl_text_l(struct archive_entry *, int,
+ const char **, size_t *, struct archive_string_conv *);
+
+
+#define archive_entry_copy_gname_l _archive_entry_copy_gname_l
+int _archive_entry_copy_gname_l(struct archive_entry *,
+ const char *, size_t, struct archive_string_conv *);
+#define archive_entry_copy_hardlink_l _archive_entry_copy_hardlink_l
+int _archive_entry_copy_hardlink_l(struct archive_entry *,
+ const char *, size_t, struct archive_string_conv *);
+#define archive_entry_copy_link_l _archive_entry_copy_link_l
+int _archive_entry_copy_link_l(struct archive_entry *,
+ const char *, size_t, struct archive_string_conv *);
+#define archive_entry_copy_pathname_l _archive_entry_copy_pathname_l
+int _archive_entry_copy_pathname_l(struct archive_entry *,
+ const char *, size_t, struct archive_string_conv *);
+#define archive_entry_copy_symlink_l _archive_entry_copy_symlink_l
+int _archive_entry_copy_symlink_l(struct archive_entry *,
+ const char *, size_t, struct archive_string_conv *);
+#define archive_entry_copy_uname_l _archive_entry_copy_uname_l
+int _archive_entry_copy_uname_l(struct archive_entry *,
+ const char *, size_t, struct archive_string_conv *);
+
+#endif /* ARCHIVE_ENTRY_LOCALE_H_INCLUDED */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_entry_paths.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_entry_paths.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,151 @@
+.\" Copyright (c) 2010 Joerg Sonnenberger
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd February 22, 2010
+.Dt ARCHIVE_ENTRY_PATHS 3
+.Os
+.Sh NAME
+.Nm archive_entry_hardlink ,
+.Nm archive_entry_hardlink_w ,
+.Nm archive_entry_set_hardlink ,
+.Nm archive_entry_copy_hardlink ,
+.Nm archive_entry_copy_hardlink_w ,
+.Nm archve_entry_update_hardlink_utf8 ,
+.Nm archive_entry_set_link ,
+.Nm archive_entry_copy_link ,
+.Nm archive_entry_copy_link_w ,
+.Nm archve_entry_update_link_utf8 ,
+.Nm archive_entry_pathname ,
+.Nm archive_entry_pathname_w ,
+.Nm archive_entry_set_pathname ,
+.Nm archive_entry_copy_pathname ,
+.Nm archive_entry_copy_pathname_w ,
+.Nm archve_entry_update_pathname_utf8 ,
+.Nm archive_entry_sourcepath ,
+.Nm archive_entry_copy_sourcepath ,
+.Nm archive_entry_symlink,
+.Nm archive_entry_symlink_w,
+.Nm archive_entry_set_symlink ,
+.Nm archive_entry_copy_symlink ,
+.Nm archive_entry_copy_symlink_w ,
+.Nm archve_entry_update_symlink_utf8
+.Nd functions for manipulating path names in archive entry descriptions
+.Sh SYNOPSIS
+.In archive_entry.h
+.Ft const char *
+.Fn archive_entry_hardlink "struct archive_entry *a"
+.Ft const wchar_t *
+.Fn archive_entry_hardlink_w "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_hardlink "struct archive_entry *a" "const char *path"
+.Ft void
+.Fn archive_entry_copy_hardlink "struct archive_entry *a" "const char *path"
+.Ft void
+.Fn archive_entry_copy_hardlink_w "struct archive_entry *a "const wchar_t *path"
+.Ft int
+.Fn archive_entry_update_hardlink_utf8 "struct archive_entry *a" "const char *path"
+.Ft void
+.Fn archive_entry_set_link "struct archive_entry *a" "const char *path"
+.Ft void
+.Fn archive_entry_copy_link "struct archive_entry *a" " const char *path"
+.Ft void
+.Fn archive_entry_copy_link_w "struct archive_entry *a" " const wchar_t *path"
+.Ft int
+.Fn archive_entry_update_link_utf8 "struct archive_entry *a" " const char *path"
+.Ft const char *
+.Fn archive_entry_pathname "struct archive_entry *a"
+.Ft const wchar_t *
+.Fn archive_entry_pathname_w "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_pathname "struct archive_entry *a" "const char *path"
+.Ft void
+.Fn archive_entry_copy_pathname "struct archive_entry *a" "const char *path"
+.Ft void
+.Fn archive_entry_copy_pathname_w "struct archive_entry *a" "const wchar_t *path"
+.Ft int
+.Fn archive_entry_update_pathname_utf8 "struct archive_entry *a" "const char *path"
+.Ft const char *
+.Fn archive_entry_sourcepath "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_copy_sourcepath "struct archive_entry *a" "const char *path"
+.Ft const char *
+.Fn archive_entry_symlink "struct archive_entry *a"
+.Ft const wchar_t *
+.Fn archive_entry_symlink_w "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_symlink "struct archive_entry *a" "const char *path"
+.Ft void
+.Fn archive_entry_copy_symlink "struct archive_entry *a" "const char *path"
+.Ft void
+.Fn archive_entry_copy_symlink_w "struct archive_entry *a" "const wchar_t *path"
+.Ft int
+.Fn archive_entry_update_symlink_utf8 "struct archive_entry *a" "const char *path"
+.Sh DESCRIPTION
+Path names supported by
+.Xr archive_entry 3 :
+.Bl -tag -width "sourcepath" -compact
+.It hardlink
+Destination of the hardlink.
+.It link
+Update only.
+For a symlink, update the destination.
+Otherwise, make the entry a hardlink and alter
+the destination for that.
+.It pathname
+Path in the archive
+.It sourcepath
+Path on the disk for use by
+.Xr archive_read_disk 3 .
+.It symlink
+Destination of the symbolic link.
+.El
+.Pp
+Path names can be provided in one of three different ways:
+.Bl -tag -width "wchar_t *"
+.It char *
+Multibyte strings in the current locale.
+.It wchar_t *
+Wide character strings in the current locale.
+The accessor functions are named
+.Fn XXX_w .
+.It UTF-8
+Unicode strings encoded as UTF-8.
+This are convience functions to update both the multibyte and wide
+character strings at the same time.
+.El
+.Pp
+The sourcepath is a pure filesystem concept and never stored in an
+archive directly.
+.Pp
+For that reason, it is only available as multibyte string.
+The link path is a convience function for conditionally setting
+hardlink or symlink destination.
+It doesn't have a corresponding get accessor function.
+.Pp
+.Fn archive_entry_set_XXX
+is an alias for
+.Fn archive_entry_copy_XXX .
+.Sh SEE ALSO
+.Xr archive 3 ,
+.Xr archive_entry 3
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_entry_perms.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_entry_perms.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,207 @@
+.\" Copyright (c) 2003-2007 Tim Kientzle
+.\" Copyright (c) 2010 Joerg Sonnenberger
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd February 22, 2010
+.Dt ARCHIVE_ENTRY_PERMS 3
+.Os
+.Sh NAME
+.Nm archive_entry_gid ,
+.Nm archive_entry_set_gid ,
+.Nm archive_entry_uid ,
+.Nm archive_entry_set_uid ,
+.Nm archive_entry_perm ,
+.Nm archive_entry_set_perm ,
+.Nm archive_entry_strmode ,
+.Nm archive_entry_uname
+.Nm archive_entry_uname_w
+.Nm archive_entry_set_uname ,
+.Nm archive_entry_copy_uname ,
+.Nm archive_entry_copy_uname_w ,
+.Nm archive_entry_update_uname_utf8 ,
+.Nm archive_entry_gname ,
+.Nm archive_entry_gname_w ,
+.Nm archive_entry_set_gname ,
+.Nm archive_entry_copy_gname ,
+.Nm archive_entry_copy_gname_w ,
+.Nm archive_entry_update_gname_utf8 ,
+.Nm archive_entry_fflags ,
+.Nm archive_entry_fflags_text ,
+.Nm archive_entry_set_fflags ,
+.Nm archive_entry_copy_fflags_text ,
+.Nm archive_entry_copy_fflags_text_w
+.Nd functions for manipulating ownership and permissions in archive entry descriptions
+.Sh SYNOPSIS
+.In archive_entry.h
+.Ft gid_t
+.Fn archive_entry_gid "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_gid "struct archive_entry *a" "gid_t gid"
+.Ft uid_t
+.Fn archive_entry_uid "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_uid "struct archive_entry *a" "uid_t uid"
+.Ft mode_t
+.Fn archive_entry_perm "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_perm "struct archive_entry *a" "mode_t mode"
+.Ft const char *
+.Fn archive_entry_strmode "struct archive_entry *a"
+.Ft const char *
+.Fn archive_entry_gname "struct archive_entry *a"
+.Ft const wchar_t *
+.Fn archive_entry_gname_w "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_gname "struct archive_entry *a" "const char *a"
+.Ft void
+.Fn archive_entry_copy_gname "struct archive_entry *a" "const char *name"
+.Ft void
+.Fn archive_entry_copy_gname_w "struct archive_entry *a" "const wchar_t *name"
+.Ft int
+.Fn archive_entry_update_gname_utf8 "struct archive_entry *a" "const char *name"
+.Ft const char *
+.Fn archive_entry_uname "struct archive_entry *a"
+.Ft const wchar_t *
+.Fn archive_entry_uname_w "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_uname "struct archive_entry *a" "const char *name"
+.Ft void
+.Fn archive_entry_copy_uname "struct archive_entry *a" "const char *name"
+.Ft void
+.Fn archive_entry_copy_uname_w "struct archive_entry *a" "const wchar_t *name"
+.Ft int
+.Fn archive_entry_update_uname_utf8 "struct archive_entry *a" "const char *name"
+.Ft void
+.Fo archive_entry_fflags
+.Fa "struct archive_entry *a"
+.Fa "unsigned long *set_bits"
+.Fa "unsigned long *clear_bits"
+.Fc
+.Ft const char *
+.Fn archive_entry_fflags_text "struct archive_entry *a"
+.Ft void
+.Fo archive_entry_set_fflags
+.Fa "struct archive_entry *a"
+.Fa "unsigned long set_bits"
+.Fa "unsigned long clear_bits"
+.Fc
+.Ft const char *
+.Fn archive_entry_copy_fflags_text "struct archive_entry *a" "const char *text"
+.Ft const wchar_t *
+.Fn archive_entry_copy_fflags_text_w "struct archive_entry *a" "const wchar_t *text"
+.Sh DESCRIPTION
+.Ss User id, group id and mode
+The functions
+.Fn archive_entry_uid ,
+.Fn archive_entry_gid ,
+and
+.Fn archive_entry_perm
+can be used to extract the user id, group id and permission from the given entry.
+The corresponding functions
+.Fn archive_entry_set_uid ,
+.Fn archive_entry_set_gid ,
+and
+.Fn archive_entry_set_perm
+store the given user id, group id and permission in the entry.
+The permission is also set as side effect of calling
+.Fn archive_entry_set_mode .
+.Pp
+.Fn archive_entry_strmode
+returns a string representation of the permission as used by the long mode of
+.Xr ls 1 .
+.Ss User and group name
+User and group names can be provided in one of three different ways:
+.Bl -tag -width "wchar_t *"
+.It char *
+Multibyte strings in the current locale.
+.It wchar_t *
+Wide character strings in the current locale.
+The accessor functions are named
+.Fn XXX_w .
+.It UTF-8
+Unicode strings encoded as UTF-8.
+This are convience functions to update both the multibyte and wide
+character strings at the same time.
+.El
+.Pp
+.Fn archive_entry_set_XXX
+is an alias for
+.Fn archive_entry_copy_XXX .
+.Ss File Flags
+File flags are transparently converted between a bitmap
+representation and a textual format.
+For example, if you set the bitmap and ask for text, the library
+will build a canonical text format.
+However, if you set a text format and request a text format,
+you will get back the same text, even if it is ill-formed.
+If you need to canonicalize a textual flags string, you should first set the
+text form, then request the bitmap form, then use that to set the bitmap form.
+Setting the bitmap format will clear the internal text representation
+and force it to be reconstructed when you next request the text form.
+.Pp
+The bitmap format consists of two integers, one containing bits
+that should be set, the other specifying bits that should be
+cleared.
+Bits not mentioned in either bitmap will be ignored.
+Usually, the bitmap of bits to be cleared will be set to zero.
+In unusual circumstances, you can force a fully-specified set
+of file flags by setting the bitmap of flags to clear to the complement
+of the bitmap of flags to set.
+(This differs from
+.Xr fflagstostr 3 ,
+which only includes names for set bits.)
+Converting a bitmap to a textual string is a platform-specific
+operation; bits that are not meaningful on the current platform
+will be ignored.
+.Pp
+The canonical text format is a comma-separated list of flag names.
+The
+.Fn archive_entry_copy_fflags_text
+and
+.Fn archive_entry_copy_fflags_text_w
+functions parse the provided text and sets the internal bitmap values.
+This is a platform-specific operation; names that are not meaningful
+on the current platform will be ignored.
+The function returns a pointer to the start of the first name that was not
+recognized, or NULL if every name was recognized.
+Note that every name \(em including names that follow an unrecognized
+name \(em will be evaluated, and the bitmaps will be set to reflect
+every name that is recognized.
+(In particular, this differs from
+.Xr strtofflags 3 ,
+which stops parsing at the first unrecognized name.)
+.Sh SEE ALSO
+.Xr archive 3 ,
+.Xr archive_entry 3 ,
+.Xr archive_entry_acl 3 ,
+.Xr archive_read_disk 3 ,
+.Xr archive_write_disk 3
+.Sh BUGS
+The platform types
+.Vt uid_t
+and
+.Vt gid_t
+are often 16 or 32 bit wide.
+In this case it is possible that the ids can not be correctly restored
+from archives and get truncated.
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_entry_sparse.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_entry_sparse.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2010-2011 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+#include "archive_entry_private.h"
+
+/*
+ * sparse handling
+ */
+
+void
+archive_entry_sparse_clear(struct archive_entry *entry)
+{
+ struct ae_sparse *sp;
+
+ while (entry->sparse_head != NULL) {
+ sp = entry->sparse_head->next;
+ free(entry->sparse_head);
+ entry->sparse_head = sp;
+ }
+ entry->sparse_tail = NULL;
+}
+
+void
+archive_entry_sparse_add_entry(struct archive_entry *entry,
+ int64_t offset, int64_t length)
+{
+ struct ae_sparse *sp;
+
+ if (offset < 0 || length < 0)
+ /* Invalid value */
+ return;
+ if (offset + length < 0 ||
+ offset + length > archive_entry_size(entry))
+ /* A value of "length" parameter is too large. */
+ return;
+ if ((sp = entry->sparse_tail) != NULL) {
+ if (sp->offset + sp->length > offset)
+ /* Invalid value. */
+ return;
+ if (sp->offset + sp->length == offset) {
+ if (sp->offset + sp->length + length < 0)
+ /* A value of "length" parameter is
+ * too large. */
+ return;
+ /* Expand existing sparse block size. */
+ sp->length += length;
+ return;
+ }
+ }
+
+ if ((sp = (struct ae_sparse *)malloc(sizeof(*sp))) == NULL)
+ /* XXX Error XXX */
+ return;
+
+ sp->offset = offset;
+ sp->length = length;
+ sp->next = NULL;
+
+ if (entry->sparse_head == NULL)
+ entry->sparse_head = entry->sparse_tail = sp;
+ else {
+ /* Add a new sparse block to the tail of list. */
+ if (entry->sparse_tail != NULL)
+ entry->sparse_tail->next = sp;
+ entry->sparse_tail = sp;
+ }
+}
+
+
+/*
+ * returns number of the sparse entries
+ */
+int
+archive_entry_sparse_count(struct archive_entry *entry)
+{
+ struct ae_sparse *sp;
+ int count = 0;
+
+ for (sp = entry->sparse_head; sp != NULL; sp = sp->next)
+ count++;
+
+ /*
+ * Sanity check if this entry is exactly sparse.
+ * If amount of sparse blocks is just one and it indicates the whole
+ * file data, we should remove it and return zero.
+ */
+ if (count == 1) {
+ sp = entry->sparse_head;
+ if (sp->offset == 0 &&
+ sp->length >= archive_entry_size(entry)) {
+ count = 0;
+ archive_entry_sparse_clear(entry);
+ }
+ }
+
+ return (count);
+}
+
+int
+archive_entry_sparse_reset(struct archive_entry * entry)
+{
+ entry->sparse_p = entry->sparse_head;
+
+ return archive_entry_sparse_count(entry);
+}
+
+int
+archive_entry_sparse_next(struct archive_entry * entry,
+ int64_t *offset, int64_t *length)
+{
+ if (entry->sparse_p) {
+ *offset = entry->sparse_p->offset;
+ *length = entry->sparse_p->length;
+
+ entry->sparse_p = entry->sparse_p->next;
+
+ return (ARCHIVE_OK);
+ } else {
+ *offset = 0;
+ *length = 0;
+ return (ARCHIVE_WARN);
+ }
+}
+
+/*
+ * end of sparse handling
+ */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_entry_stat.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_entry_stat.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,272 @@
+.\" Copyright (c) 2010 Joerg Sonnenberger
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd May 12, 2008
+.Dt ARCHIVE_ENTRY 3
+.Os
+.Sh NAME
+.Nm archive_entry_stat ,
+.Nm archive_entry_copy_stat ,
+.Nm archive_entry_filetype ,
+.Nm archive_entry_set_filetype ,
+.Nm archive_entry_mode ,
+.Nm archive_entry_set_mode ,
+.Nm archive_entry_size ,
+.Nm archive_entry_size_is_set ,
+.Nm archive_entry_set_size ,
+.Nm archive_entry_unset_size ,
+.Nm archive_entry_dev ,
+.Nm archive_entry_set_dev ,
+.Nm archive_entry_dev_is_set ,
+.Nm archive_entry_devmajor ,
+.Nm archive_entry_set_devmajor ,
+.Nm archive_entry_devminor ,
+.Nm archive_entry_set_devminor ,
+.Nm archive_entry_ino ,
+.Nm archive_entry_set_ino ,
+.Nm archive_entry_ino_is_set ,
+.Nm archive_entry_ino64 ,
+.Nm archive_entry_set_ino64 ,
+.Nm archive_entry_nlink ,
+.Nm archive_entry_rdev ,
+.Nm archive_entry_set_rdev ,
+.Nm archive_entry_rdevmajor ,
+.Nm archive_entry_set_rdevmajor ,
+.Nm archive_entry_rdevminor ,
+.Nm archive_entry_set_rdevminor ,
+.Nd accessor functions for manipulating archive entry descriptions
+.Sh SYNOPSIS
+.In archive_entry.h
+.Ft const struct stat *
+.Fn archive_entry_stat "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_copy_stat "struct archive_entry *a" "const struct stat *sb"
+.Ft mode_t
+.Fn archive_entry_filetype "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_filetype "struct archive_entry *a" "unsigned int type"
+.Ft mode_t
+.Fn archive_entry_mode "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_mode "struct archive_entry *a" "mode_t mode"
+.Ft int64_t
+.Fn archive_entry_size "struct archive_entry *a"
+.Ft int
+.Fn archive_entry_size_is_set "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_size "struct archive_entry *a" "int64_t size"
+.Ft void
+.Fn archive_entry_unset_size "struct archive_entry *a"
+.Ft dev_t
+.Fn archive_entry_dev "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_dev "struct archive_entry *a" "dev_t dev"
+.Ft int
+.Fn archive_entry_dev_is_set "struct archive_entry *a"
+.Ft dev_t
+.Fn archive_entry_devmajor "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_devmajor "struct archive_entry *a" "dev_t major"
+.Ft dev_t
+.Fn archive_entry_devminor "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_devminor "struct archive_entry *a" "dev_t minor"
+.Ft ino_t
+.Fn archive_entry_ino "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_ino "struct archive_entry *a" "unsigned long ino"
+.Ft int
+.Fn archive_entry_ino_is_set "struct archive_entry *a"
+.Ft int64_t
+.Fn archive_entry_ino64 "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_ino64 "struct archive_entry *a" "int64_t ino"
+.Ft unsigned int
+.Fn archive_entry_nlink "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_nlink "struct archive_entry *a" "unsigned int count"
+.Ft dev_t
+.Fn archive_entry_rdev "struct archive_entry *a"
+.Ft dev_t
+.Fn archive_entry_rdevmajor "struct archive_entry *a"
+.Ft dev_t
+.Fn archive_entry_rdevminor "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_rdev "struct archive_entry *a" "dev_t dev"
+.Ft void
+.Fn archive_entry_set_rdevmajor "struct archive_entry *a" "dev_t major"
+.Ft void
+.Fn archive_entry_set_rdevminor "struct archive_entry *a" "dev_t minor"
+.Sh DESCRIPTION
+.Ss Copying to and from Vt struct stat
+The function
+.Fn archive_entry_stat
+converts the various fields stored in the archive entry to the format
+used by
+.Xr stat 2 .
+The return value remains valid until either
+.Fn archive_entry_clear
+or
+.Fn archive_entry_free
+is called.
+It is not affected by calls to the set accessor functions.
+It currently sets the following values in
+.Vt struct stat :
+.Vt st_atime ,
+.Vt st_ctime ,
+.Vt st_dev ,
+.Vt st_gid ,
+.Vt st_ino ,
+.Vt st_mode ,
+.Vt st_mtime ,
+.Vt st_nlink ,
+.Vt st_rdev ,
+.Vt st_size ,
+.Vt st_uid .
+In addition,
+.Vt st_birthtime
+and high-precision information for time-related fields
+will be included on platforms that support it.
+.Pp
+The function
+.Fn archive_entry_copy_stat
+copies fields from the platform's
+.Vt struct stat .
+Fields not provided by
+.Vt struct stat
+are unchanged.
+.Ss General accessor functions
+The functions
+.Fn archive_entry_filetype
+and
+.Fn archive_entry_set_filetype
+get respectively set the filetype.
+The file type is one of the following constants:
+.Bl -tag -width "AE_IFSOCK" -compact -offset indent
+.It AE_IFREG
+Regular file
+.It AE_IFLNK
+Symbolic link
+.It AE_IFSOCK
+Socket
+.It AE_IFCHR
+Character device
+.It AE_IFBLK
+Block device
+.It AE_IFDIR
+Directory
+.It AE_IFIFO
+Named pipe (fifo)
+.El
+Not all file types are supported by all platforms.
+The constants used by
+.Xr stat 2
+may have different numeric values from the
+corresponding constants above.
+.Pp
+The functions
+.Fn archive_entry_mode
+and
+.Fn archive_entry_set_mode
+get/set a combination of file type and permissions and provide the
+equivalent of
+.Va st_mode .
+Use of
+.Fn archive_entry_filetype
+and
+.Fn archive_entry_perm
+for getting and
+.Fn archive_entry_set_filetype
+and
+.Fn archive_entry_set_perm
+for setting is recommended.
+.Pp
+The function
+.Fn archive_entry_size
+returns the file size, if it has been set, and 0 otherwise.
+.Fn archive_entry_size
+can be used to query that status.
+.Fn archive_entry_set_size
+and
+.Fn archive_entry_unset_size
+set and unset the size, respectively.
+.Pp
+The number of references (hardlinks) can be obtained by calling
+.Fn archive_entry_nlinks
+and set with
+.Fn archive_entry_set_nlinks .
+.Ss Identifying unique files
+The functions
+.Fn archive_entry_dev
+and
+.Fn archive_entry_ino64
+are used by
+.Xr archive_entry_linkify 3
+to find hardlinks.
+The pair of device and inode is suppossed to identify hardlinked files.
+.Pp
+The device major and minor number can be obtained independently using
+.Fn archive_entry_devmajor
+and
+.Fn archive_entry_devminor .
+The device can be set either via
+.Fn archive_entry_set_dev
+or by the combination of major and minor number using
+.Fn archive_entry_set_devmajor
+and
+.Fn archive_entry_set_devminor .
+.Pp
+The inode number can be obtained using
+.Fn archive_entry_ino .
+This is a legacy interface that uses the platform
+.Vt ino_t ,
+which may be very small.
+To set the inode number,
+.Fn archive_entry_set_ino64
+is the preferred interface.
+.Ss Accessor functions for block and character devices
+Block and character devices are characterised either using a device number
+or a pair of major and minor number.
+The combined device number can be obtained with
+.Fn archive_device_rdev
+and set with
+.Fn archive_device_set_rdev .
+The major and minor numbers are accessed by
+.Fn archive_device_rdevmajor ,
+.Fn archive_device_rdevminor
+.Fn archive_device_set_rdevmajor
+and
+.Fn archive_device_set_rdevminor .
+.Pp
+The process of splitting the combined device number into major and
+minor number and the reverse process of combing them differs between
+platforms.
+Some archive formats use the combined form, while other formats use
+the split form.
+.Sh SEE ALSO
+.Xr archive 3 ,
+.Xr archive_entry_acl 3 ,
+.Xr archive_entry_perms 3 ,
+.Xr archive_entry_time 3 ,
+.Xr stat 2
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_entry_time.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_entry_time.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,127 @@
+.\" Copyright (c) 2003-2007 Tim Kientzle
+.\" Copyright (c) 2010 Joerg Sonnenberger
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libarchive/archive_entry.3,v 1.18 2008/05/26 17:00:22 kientzle Exp $
+.\"
+.Dd February 21, 2010
+.Dt ARCHIVE_ENTRY_TIME 3
+.Os
+.Sh NAME
+.Nm archive_entry_atime ,
+.Nm archive_entry_atime_nsec ,
+.Nm archive_entry_atime_is_set ,
+.Nm archive_entry_set_atime ,
+.Nm archive_entry_unset_atime ,
+.Nm archive_entry_birthtime ,
+.Nm archive_entry_birthtime_nsec ,
+.Nm archive_entry_birthtime_is_set ,
+.Nm archive_entry_set_birthtime ,
+.Nm archive_entry_unset_birthtime ,
+.Nm archive_entry_ctime ,
+.Nm archive_entry_ctime_nsec ,
+.Nm archive_entry_ctime_is_set ,
+.Nm archive_entry_set_ctime ,
+.Nm archive_entry_unset_ctime ,
+.Nm archive_entry_mtime ,
+.Nm archive_entry_mtime_nsec ,
+.Nm archive_entry_mtime_is_set ,
+.Nm archive_entry_set_mtime ,
+.Nm archive_entry_unset_mtime ,
+.Nd functions for manipulating times in archive entry descriptions
+.Sh SYNOPSIS
+.In archive_entry.h
+.Ft time_t
+.Fn archive_entry_atime "struct archive_entry *a"
+.Ft long
+.Fn archive_entry_atime_nsec "struct archive_entry *a"
+.Ft int
+.Fn archive_entry_atime_is_set "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_atime "struct archive_entry *a" "time_t sec" "long nanosec"
+.Ft void
+.Fn archive_entry_unset_atime "struct archive_entry *a"
+.Ft time_t
+.Fn archive_entry_birthtime "struct archive_entry *a"
+.Ft long
+.Fn archive_entry_birthtime_nsec "struct archive_entry *a"
+.Ft int
+.Fn archive_entry_birthtime_is_set "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_birthtime "struct archive_entry *a" "time_t sec" "long nanosec"
+.Ft void
+.Fn archive_entry_unset_birthtime "struct archive_entry *a"
+.Ft time_t
+.Fn archive_entry_ctime "struct archive_entry *a"
+.Ft long
+.Fn archive_entry_ctime_nsec "struct archive_entry *a"
+.Ft int
+.Fn archive_entry_ctime_is_set "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_ctime "struct archive_entry *a" "time_t sec" "long nanosec"
+.Ft void
+.Fn archive_entry_unset_ctime "struct archive_entry *a"
+.Ft time_t
+.Fn archive_entry_mtime "struct archive_entry *a"
+.Ft long
+.Fn archive_entry_mtime_nsec "struct archive_entry *a"
+.Ft int
+.Fn archive_entry_mtime_is_set "struct archive_entry *a"
+.Ft void
+.Fn archive_entry_set_mtime "struct archive_entry *a" "time_t sec" "long nanosec"
+.Ft void
+.Fn archive_entry_unset_mtime "struct archive_entry *a"
+.Sh DESCRIPTION
+These functions create and manipulate the time fields in an
+.Vt archive_entry .
+Supported time fields are atime (access time), birthtime (creation time),
+ctime (last time an inode property was changed) and mtime (modification time).
+.Pp
+.Xr libarchive 3
+provides a high-resolution interface.
+The timestamps are truncated automatically depending on the archive format
+(for archiving) or the filesystem capabilities (for restoring).
+.Pp
+All timestamp fields are optional.
+The
+.Fn XXX_unset
+functions can be used to mark the corresponding field as missing.
+The current state can be queried using
+.Fn XXX_is_set .
+Unset time fields have a second and nanosecond field of 0.
+.Sh SEE ALSO
+.Xr archive 3 ,
+.Xr archive_entry 3
+.Sh HISTORY
+The
+.Nm libarchive
+library first appeared in
+.Fx 5.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libarchive
+library was written by
+.An Tim Kientzle Aq kientzle at acm.org .
+.\" .Sh BUGS
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_hash.h
--- a/head/contrib/libarchive/libarchive/archive_hash.h Fri Mar 02 16:58:39 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,309 +0,0 @@
-/*-
- * Copyright (c) 2009 Joerg Sonnenberger
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD: head/contrib/libarchive/libarchive/archive_hash.h 228763 2011-12-21 11:13:29Z mm $
- */
-
-#ifndef __LIBARCHIVE_BUILD
-#error This header is only to be used internally to libarchive.
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-/*
- * Hash function support in various Operating Systems:
- *
- * NetBSD:
- * - MD5 and SHA1 in libc: without _ after algorithm name
- * - SHA2 in libc: with _ after algorithm name
- *
- * OpenBSD:
- * - MD5, SHA1 and SHA2 in libc: without _ after algorithm name
- * - OpenBSD 4.4 and earlier have SHA2 in libc with _ after algorithm name
- *
- * DragonFly and FreeBSD (XXX not used yet):
- * - MD5 and SHA1 in libmd: without _ after algorithm name
- * - SHA256: with _ after algorithm name
- *
- * Mac OS X (10.4 and later):
- * - MD5, SHA1 and SHA2 in libSystem: with CC_ prefix and _ after algorithm name
- *
- * OpenSSL:
- * - MD5, SHA1 and SHA2 in libcrypto: with _ after algorithm name
- *
- * Windows:
- * - MD5, SHA1 and SHA2 in archive_windows.c: without algorithm name
- * and with __la_ prefix.
- */
-#if defined(ARCHIVE_HASH_MD5_WIN) ||\
- defined(ARCHIVE_HASH_SHA1_WIN) || defined(ARCHIVE_HASH_SHA256_WIN) ||\
- defined(ARCHIVE_HASH_SHA384_WIN) || defined(ARCHIVE_HASH_SHA512_WIN)
-#include <wincrypt.h>
-typedef struct {
- int valid;
- HCRYPTPROV cryptProv;
- HCRYPTHASH hash;
-} Digest_CTX;
-extern void __la_hash_Init(Digest_CTX *, ALG_ID);
-extern void __la_hash_Final(unsigned char *, size_t, Digest_CTX *);
-extern void __la_hash_Update(Digest_CTX *, const unsigned char *, size_t);
-#endif
-
-#if defined(ARCHIVE_HASH_MD5_LIBC)
-# include <md5.h>
-# define ARCHIVE_HAS_MD5
-typedef MD5_CTX archive_md5_ctx;
-# define archive_md5_init(ctx) MD5Init(ctx)
-# define archive_md5_final(ctx, buf) MD5Final(buf, ctx)
-# define archive_md5_update(ctx, buf, n) MD5Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_MD5_LIBMD)
-# include <md5.h>
-# define ARCHIVE_HAS_MD5
-typedef MD5_CTX archive_md5_ctx;
-# define archive_md5_init(ctx) MD5Init(ctx)
-# define archive_md5_final(ctx, buf) MD5Final(buf, ctx)
-# define archive_md5_update(ctx, buf, n) MD5Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_MD5_LIBSYSTEM)
-# include <CommonCrypto/CommonDigest.h>
-# define ARCHIVE_HAS_MD5
-typedef CC_MD5_CTX archive_md5_ctx;
-# define archive_md5_init(ctx) CC_MD5_Init(ctx)
-# define archive_md5_final(ctx, buf) CC_MD5_Final(buf, ctx)
-# define archive_md5_update(ctx, buf, n) CC_MD5_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_MD5_OPENSSL)
-# include <openssl/md5.h>
-# define ARCHIVE_HAS_MD5
-typedef MD5_CTX archive_md5_ctx;
-# define archive_md5_init(ctx) MD5_Init(ctx)
-# define archive_md5_final(ctx, buf) MD5_Final(buf, ctx)
-# define archive_md5_update(ctx, buf, n) MD5_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_MD5_WIN)
-# define ARCHIVE_HAS_MD5
-# define MD5_DIGEST_LENGTH 16
-typedef Digest_CTX archive_md5_ctx;
-# define archive_md5_init(ctx) __la_hash_Init(ctx, CALG_MD5)
-# define archive_md5_final(ctx, buf) __la_hash_Final(buf, MD5_DIGEST_LENGTH, ctx)
-# define archive_md5_update(ctx, buf, n) __la_hash_Update(ctx, buf, n)
-#endif
-
-#if defined(ARCHIVE_HASH_RMD160_LIBC)
-# include <rmd160.h>
-# define ARCHIVE_HAS_RMD160
-typedef RMD160_CTX archive_rmd160_ctx;
-# define archive_rmd160_init(ctx) RMD160Init(ctx)
-# define archive_rmd160_final(ctx, buf) RMD160Final(buf, ctx)
-# define archive_rmd160_update(ctx, buf, n) RMD160Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_RMD160_OPENSSL)
-# include <openssl/ripemd.h>
-# define ARCHIVE_HAS_RMD160
-typedef RIPEMD160_CTX archive_rmd160_ctx;
-# define archive_rmd160_init(ctx) RIPEMD160_Init(ctx)
-# define archive_rmd160_final(ctx, buf) RIPEMD160_Final(buf, ctx)
-# define archive_rmd160_update(ctx, buf, n) RIPEMD160_Update(ctx, buf, n)
-#endif
-
-#if defined(ARCHIVE_HASH_SHA1_LIBC)
-# include <sha1.h>
-# define ARCHIVE_HAS_SHA1
-typedef SHA1_CTX archive_sha1_ctx;
-# define archive_sha1_init(ctx) SHA1Init(ctx)
-# define archive_sha1_final(ctx, buf) SHA1Final(buf, ctx)
-# define archive_sha1_update(ctx, buf, n) SHA1Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA1_LIBMD)
-# include <sha.h>
-# define ARCHIVE_HAS_SHA1
-typedef SHA1_CTX archive_sha1_ctx;
-# define archive_sha1_init(ctx) SHA1_Init(ctx)
-# define archive_sha1_final(ctx, buf) SHA1_Final(buf, ctx)
-# define archive_sha1_update(ctx, buf, n) SHA1_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA1_LIBSYSTEM)
-# include <CommonCrypto/CommonDigest.h>
-# define ARCHIVE_HAS_SHA1
-typedef CC_SHA1_CTX archive_sha1_ctx;
-# define archive_sha1_init(ctx) CC_SHA1_Init(ctx)
-# define archive_sha1_final(ctx, buf) CC_SHA1_Final(buf, ctx)
-# define archive_sha1_update(ctx, buf, n) CC_SHA1_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA1_OPENSSL)
-# include <openssl/sha.h>
-# define ARCHIVE_HAS_SHA1
-typedef SHA_CTX archive_sha1_ctx;
-# define archive_sha1_init(ctx) SHA1_Init(ctx)
-# define archive_sha1_final(ctx, buf) SHA1_Final(buf, ctx)
-# define archive_sha1_update(ctx, buf, n) SHA1_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA1_WIN)
-# define ARCHIVE_HAS_SHA1
-# define SHA1_DIGEST_LENGTH 20
-typedef Digest_CTX archive_sha1_ctx;
-# define archive_sha1_init(ctx) __la_hash_Init(ctx, CALG_SHA1)
-# define archive_sha1_final(ctx, buf) __la_hash_Final(buf, SHA1_DIGEST_LENGTH, ctx)
-# define archive_sha1_update(ctx, buf, n) __la_hash_Update(ctx, buf, n)
-#endif
-
-#if defined(ARCHIVE_HASH_SHA256_LIBC)
-# include <sha2.h>
-# define ARCHIVE_HAS_SHA256
-typedef SHA256_CTX archive_sha256_ctx;
-# define archive_sha256_init(ctx) SHA256_Init(ctx)
-# define archive_sha256_final(ctx, buf) SHA256_Final(buf, ctx)
-# define archive_sha256_update(ctx, buf, n) SHA256_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA256_LIBC2)
-# include <sha2.h>
-# define ARCHIVE_HAS_SHA256
-typedef SHA256_CTX archive_sha256_ctx;
-# define archive_sha256_init(ctx) SHA256Init(ctx)
-# define archive_sha256_final(ctx, buf) SHA256Final(buf, ctx)
-# define archive_sha256_update(ctx, buf, n) SHA256Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA256_LIBC3)
-# include <sha2.h>
-# define ARCHIVE_HAS_SHA256
-typedef SHA2_CTX archive_sha256_ctx;
-# define archive_sha256_init(ctx) SHA256Init(ctx)
-# define archive_sha256_final(ctx, buf) SHA256Final(buf, ctx)
-# define archive_sha256_update(ctx, buf, n) SHA256Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA256_LIBMD)
-# include <sha256.h>
-# define ARCHIVE_HAS_SHA256
-typedef SHA256_CTX archive_sha256_ctx;
-# define archive_sha256_init(ctx) SHA256_Init(ctx)
-# define archive_sha256_final(ctx, buf) SHA256_Final(buf, ctx)
-# define archive_sha256_update(ctx, buf, n) SHA256_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA256_LIBSYSTEM)
-# include <CommonCrypto/CommonDigest.h>
-# define ARCHIVE_HAS_SHA256
-typedef CC_SHA256_CTX archive_shs256_ctx;
-# define archive_shs256_init(ctx) CC_SHA256_Init(ctx)
-# define archive_shs256_final(ctx, buf) CC_SHA256_Final(buf, ctx)
-# define archive_shs256_update(ctx, buf, n) CC_SHA256_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA256_OPENSSL)
-# include <openssl/sha.h>
-# define ARCHIVE_HAS_SHA256
-typedef SHA256_CTX archive_sha256_ctx;
-# define archive_sha256_init(ctx) SHA256_Init(ctx)
-# define archive_sha256_final(ctx, buf) SHA256_Final(buf, ctx)
-# define archive_sha256_update(ctx, buf, n) SHA256_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA256_WIN)
-# define ARCHIVE_HAS_SHA256
-# define SHA256_DIGEST_LENGTH 32
-typedef Digest_CTX archive_sha256_ctx;
-# define archive_sha256_init(ctx) __la_hash_Init(ctx, CALG_SHA_256)
-# define archive_sha256_final(ctx, buf) __la_hash_Final(buf, SHA256_DIGEST_LENGTH, ctx)
-# define archive_sha256_update(ctx, buf, n) __la_hash_Update(ctx, buf, n)
-#endif
-
-#if defined(ARCHIVE_HASH_SHA384_LIBC)
-# include <sha2.h>
-# define ARCHIVE_HAS_SHA384
-typedef SHA384_CTX archive_sha384_ctx;
-# define archive_sha384_init(ctx) SHA384_Init(ctx)
-# define archive_sha384_final(ctx, buf) SHA384_Final(buf, ctx)
-# define archive_sha384_update(ctx, buf, n) SHA384_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA384_LIBC2)
-# include <sha2.h>
-# define ARCHIVE_HAS_SHA384
-typedef SHA384_CTX archive_sha384_ctx;
-# define archive_sha384_init(ctx) SHA384Init(ctx)
-# define archive_sha384_final(ctx, buf) SHA384Final(buf, ctx)
-# define archive_sha384_update(ctx, buf, n) SHA384Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA384_LIBC3)
-# include <sha2.h>
-# define ARCHIVE_HAS_SHA384
-typedef SHA2_CTX archive_sha384_ctx;
-# define archive_sha384_init(ctx) SHA384Init(ctx)
-# define archive_sha384_final(ctx, buf) SHA384Final(buf, ctx)
-# define archive_sha384_update(ctx, buf, n) SHA384Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA384_LIBSYSTEM)
-# include <CommonCrypto/CommonDigest.h>
-# define ARCHIVE_HAS_SHA384
-typedef CC_SHA512_CTX archive_shs384_ctx;
-# define archive_shs384_init(ctx) CC_SHA384_Init(ctx)
-# define archive_shs384_final(ctx, buf) CC_SHA384_Final(buf, ctx)
-# define archive_shs384_update(ctx, buf, n) CC_SHA384_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA384_OPENSSL)
-# include <openssl/sha.h>
-# define ARCHIVE_HAS_SHA384
-typedef SHA512_CTX archive_sha384_ctx;
-# define archive_sha384_init(ctx) SHA384_Init(ctx)
-# define archive_sha384_final(ctx, buf) SHA384_Final(buf, ctx)
-# define archive_sha384_update(ctx, buf, n) SHA384_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA384_WIN)
-# define ARCHIVE_HAS_SHA384
-# define SHA384_DIGEST_LENGTH 48
-typedef Digest_CTX archive_sha384_ctx;
-# define archive_sha384_init(ctx) __la_hash_Init(ctx, CALG_SHA_384)
-# define archive_sha384_final(ctx, buf) __la_hash_Final(buf, SHA384_DIGEST_LENGTH, ctx)
-# define archive_sha384_update(ctx, buf, n) __la_hash_Update(ctx, buf, n)
-#endif
-
-#if defined(ARCHIVE_HASH_SHA512_LIBC)
-# include <sha2.h>
-# define ARCHIVE_HAS_SHA512
-typedef SHA512_CTX archive_sha512_ctx;
-# define archive_sha512_init(ctx) SHA512_Init(ctx)
-# define archive_sha512_final(ctx, buf) SHA512_Final(buf, ctx)
-# define archive_sha512_update(ctx, buf, n) SHA512_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA512_LIBC2)
-# include <sha2.h>
-# define ARCHIVE_HAS_SHA512
-typedef SHA512_CTX archive_sha512_ctx;
-# define archive_sha512_init(ctx) SHA512Init(ctx)
-# define archive_sha512_final(ctx, buf) SHA512Final(buf, ctx)
-# define archive_sha512_update(ctx, buf, n) SHA512Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA512_LIBC3)
-# include <sha2.h>
-# define ARCHIVE_HAS_SHA512
-typedef SHA2_CTX archive_sha512_ctx;
-# define archive_sha512_init(ctx) SHA512Init(ctx)
-# define archive_sha512_final(ctx, buf) SHA512Final(buf, ctx)
-# define archive_sha512_update(ctx, buf, n) SHA512Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA512_LIBMD)
-# include <sha512.h>
-# define ARCHIVE_HAS_SHA512
-typedef SHA512_CTX archive_sha512_ctx;
-# define archive_sha512_init(ctx) SHA512_Init(ctx)
-# define archive_sha512_final(ctx, buf) SHA512_Final(buf, ctx)
-# define archive_sha512_update(ctx, buf, n) SHA512_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA512_LIBSYSTEM)
-# include <CommonCrypto/CommonDigest.h>
-# define ARCHIVE_HAS_SHA512
-typedef CC_SHA512_CTX archive_shs512_ctx;
-# define archive_shs512_init(ctx) CC_SHA512_Init(ctx)
-# define archive_shs512_final(ctx, buf) CC_SHA512_Final(buf, ctx)
-# define archive_shs512_update(ctx, buf, n) CC_SHA512_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA512_OPENSSL)
-# include <openssl/sha.h>
-# define ARCHIVE_HAS_SHA512
-typedef SHA512_CTX archive_sha512_ctx;
-# define archive_sha512_init(ctx) SHA512_Init(ctx)
-# define archive_sha512_final(ctx, buf) SHA512_Final(buf, ctx)
-# define archive_sha512_update(ctx, buf, n) SHA512_Update(ctx, buf, n)
-#elif defined(ARCHIVE_HASH_SHA512_WIN)
-# define ARCHIVE_HAS_SHA512
-# define SHA512_DIGEST_LENGTH 64
-typedef Digest_CTX archive_sha512_ctx;
-# define archive_sha512_init(ctx) __la_hash_Init(ctx, CALG_SHA_512)
-# define archive_sha512_final(ctx, buf) __la_hash_Final(buf, SHA512_DIGEST_LENGTH, ctx)
-# define archive_sha512_update(ctx, buf, n) __la_hash_Update(ctx, buf, n)
-#endif
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_options.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_options.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2011 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive_options_private.h"
+
+static const char *
+parse_option(const char **str,
+ const char **mod, const char **opt, const char **val);
+
+int
+_archive_set_option(struct archive *a,
+ const char *m, const char *o, const char *v,
+ int magic, const char *fn, option_handler use_option)
+{
+ const char *mp, *op, *vp;
+ int r;
+
+ archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
+
+ mp = m != NULL && m[0] == '\0' ? NULL : m;
+ op = o != NULL && o[0] == '\0' ? NULL : o;
+ vp = v != NULL && v[0] == '\0' ? NULL : v;
+
+ if (op == NULL && vp == NULL)
+ return (ARCHIVE_OK);
+ if (op == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option");
+ return (ARCHIVE_FAILED);
+ }
+
+ r = use_option(a, mp, op, vp);
+ if (r == ARCHIVE_WARN - 1) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Unknown module name: `%s'", mp);
+ return (ARCHIVE_FAILED);
+ }
+ if (r == ARCHIVE_WARN) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Undefined option: `%s%s%s%s%s%s'",
+ vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:"");
+ return (ARCHIVE_FAILED);
+ }
+ return (r);
+}
+
+int
+_archive_set_either_option(struct archive *a, const char *m, const char *o, const char *v,
+ option_handler use_format_option, option_handler use_filter_option)
+{
+ int r1, r2;
+
+ if (o == NULL && v == NULL)
+ return (ARCHIVE_OK);
+ if (o == NULL)
+ return (ARCHIVE_FAILED);
+
+ r1 = use_format_option(a, m, o, v);
+ if (r1 == ARCHIVE_FATAL)
+ return (ARCHIVE_FATAL);
+
+ r2 = use_filter_option(a, m, o, v);
+ if (r2 == ARCHIVE_FATAL)
+ return (ARCHIVE_FATAL);
+
+ return r1 > r2 ? r1 : r2;
+}
+
+int
+_archive_set_options(struct archive *a, const char *options,
+ int magic, const char *fn, option_handler use_option)
+{
+ int allok = 1, anyok = 0, r;
+ char *data;
+ const char *s, *mod, *opt, *val;
+
+ archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
+
+ if (options == NULL || options[0] == '\0')
+ return ARCHIVE_OK;
+
+ data = (char *)malloc(strlen(options) + 1);
+ strcpy(data, options);
+ s = (const char *)data;
+
+ do {
+ mod = opt = val = NULL;
+
+ parse_option(&s, &mod, &opt, &val);
+
+ r = use_option(a, mod, opt, val);
+ if (r == ARCHIVE_FATAL) {
+ free(data);
+ return (ARCHIVE_FATAL);
+ }
+ if (r == ARCHIVE_FAILED && mod != NULL) {
+ free(data);
+ return (ARCHIVE_FAILED);
+ }
+ if (r == ARCHIVE_WARN - 1) {
+ /* The module name is wrong. */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Unknown module name: `%s'", mod);
+ free(data);
+ return (ARCHIVE_FAILED);
+ }
+ if (r == ARCHIVE_WARN) {
+ /* The option name is wrong. No-one used this. */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Undefined option: `%s%s%s'",
+ mod?mod:"", mod?":":"", opt);
+ free(data);
+ return (ARCHIVE_FAILED);
+ }
+ if (r == ARCHIVE_OK)
+ anyok = 1;
+ else
+ allok = 0;
+ } while (s != NULL);
+
+ free(data);
+ return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED;
+}
+
+static const char *
+parse_option(const char **s, const char **m, const char **o, const char **v)
+{
+ const char *end, *mod, *opt, *val;
+ char *p;
+
+ end = NULL;
+ mod = NULL;
+ opt = *s;
+ val = "1";
+
+ p = strchr(opt, ',');
+
+ if (p != NULL) {
+ *p = '\0';
+ end = ((const char *)p) + 1;
+ }
+
+ if (0 == strlen(opt)) {
+ *s = end;
+ *m = NULL;
+ *o = NULL;
+ *v = NULL;
+ return end;
+ }
+
+ p = strchr(opt, ':');
+ if (p != NULL) {
+ *p = '\0';
+ mod = opt;
+ opt = ++p;
+ }
+
+ p = strchr(opt, '=');
+ if (p != NULL) {
+ *p = '\0';
+ val = ++p;
+ } else if (opt[0] == '!') {
+ ++opt;
+ val = NULL;
+ }
+
+ *s = end;
+ *m = mod;
+ *o = opt;
+ *v = val;
+
+ return end;
+}
+
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_options_private.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_options_private.h Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2011 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive_private.h"
+
+typedef int (*option_handler)(struct archive *a,
+ const char *mod, const char *opt, const char *val);
+
+int
+_archive_set_option(struct archive *a,
+ const char *mod, const char *opt, const char *val,
+ int magic, const char *fn, option_handler use_option);
+
+int
+_archive_set_options(struct archive *a, const char *options,
+ int magic, const char *fn, option_handler use_option);
+
+int
+_archive_set_either_option(struct archive *a,
+ const char *m, const char *o, const char *v,
+ option_handler use_format_option, option_handler use_filter_option);
+
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_ppmd7.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_ppmd7.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,1164 @@
+/* Ppmd7.c -- PPMdH codec
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "archive_platform.h"
+
+#include <memory.h>
+
+#include "archive_ppmd7_private.h"
+
+#ifdef PPMD_32BIT
+ #define Ppmd7_GetPtr(p, ptr) (ptr)
+ #define Ppmd7_GetContext(p, ptr) (ptr)
+ #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats)
+#else
+ #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
+ #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs)))
+ #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats)))
+#endif
+
+#define Ppmd7_GetBinSumm(p) \
+ &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \
+ p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \
+ (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \
+ 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \
+ ((p->RunLength >> 26) & 0x20)]
+
+#define kTopValue (1 << 24)
+#define MAX_FREQ 124
+#define UNIT_SIZE 12
+
+#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
+#define U2I(nu) (p->Units2Indx[(nu) - 1])
+#define I2U(indx) (p->Indx2Units[indx])
+
+#ifdef PPMD_32BIT
+ #define REF(ptr) (ptr)
+#else
+ #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
+#endif
+
+#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
+
+#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
+#define STATS(ctx) Ppmd7_GetStats(p, ctx)
+#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx)
+#define SUFFIX(ctx) CTX((ctx)->Suffix)
+
+static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
+static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+
+typedef CPpmd7_Context * CTX_PTR;
+
+struct CPpmd7_Node_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd7_Node_ *
+ #else
+ UInt32
+ #endif
+ CPpmd7_Node_Ref;
+
+typedef struct CPpmd7_Node_
+{
+ UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */
+ UInt16 NU;
+ CPpmd7_Node_Ref Next; /* must be at offset >= 4 */
+ CPpmd7_Node_Ref Prev;
+} CPpmd7_Node;
+
+#ifdef PPMD_32BIT
+ #define NODE(ptr) (ptr)
+#else
+ #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs)))
+#endif
+
+static void Ppmd7_Update1(CPpmd7 *p);
+static void Ppmd7_Update1_0(CPpmd7 *p);
+static void Ppmd7_Update2(CPpmd7 *p);
+static void Ppmd7_UpdateBin(CPpmd7 *p);
+static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked,
+ UInt32 *scale);
+
+/* ----------- Base ----------- */
+
+static void Ppmd7_Construct(CPpmd7 *p)
+{
+ unsigned i, k, m;
+
+ p->Base = 0;
+
+ for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
+ do { p->Units2Indx[k++] = (Byte)i; } while(--step);
+ p->Indx2Units[i] = (Byte)k;
+ }
+
+ p->NS2BSIndx[0] = (0 << 1);
+ p->NS2BSIndx[1] = (1 << 1);
+ memset(p->NS2BSIndx + 2, (2 << 1), 9);
+ memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
+
+ for (i = 0; i < 3; i++)
+ p->NS2Indx[i] = (Byte)i;
+ for (m = i, k = 1; i < 256; i++)
+ {
+ p->NS2Indx[i] = (Byte)m;
+ if (--k == 0)
+ k = (++m) - 2;
+ }
+
+ memset(p->HB2Flag, 0, 0x40);
+ memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40);
+}
+
+static void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->Base);
+ p->Size = 0;
+ p->Base = 0;
+}
+
+static Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
+{
+ if (p->Base == 0 || p->Size != size)
+ {
+ Ppmd7_Free(p, alloc);
+ p->AlignOffset =
+ #ifdef PPMD_32BIT
+ (4 - size) & 3;
+ #else
+ 4 - (size & 3);
+ #endif
+ if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size
+ #ifndef PPMD_32BIT
+ + UNIT_SIZE
+ #endif
+ )) == 0)
+ return False;
+ p->Size = size;
+ }
+ return True;
+}
+
+static void InsertNode(CPpmd7 *p, void *node, unsigned indx)
+{
+ *((CPpmd_Void_Ref *)node) = p->FreeList[indx];
+ p->FreeList[indx] = REF(node);
+}
+
+static void *RemoveNode(CPpmd7 *p, unsigned indx)
+{
+ CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]);
+ p->FreeList[indx] = *node;
+ return node;
+}
+
+static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
+{
+ unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
+ ptr = (Byte *)ptr + U2B(I2U(newIndx));
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
+ }
+ InsertNode(p, ptr, i);
+}
+
+static void GlueFreeBlocks(CPpmd7 *p)
+{
+ #ifdef PPMD_32BIT
+ CPpmd7_Node headItem;
+ CPpmd7_Node_Ref head = &headItem;
+ #else
+ CPpmd7_Node_Ref head = p->AlignOffset + p->Size;
+ #endif
+
+ CPpmd7_Node_Ref n = head;
+ unsigned i;
+
+ p->GlueCount = 255;
+
+ /* create doubly-linked list of free blocks */
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ UInt16 nu = I2U(i);
+ CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i];
+ p->FreeList[i] = 0;
+ while (next != 0)
+ {
+ CPpmd7_Node *node = NODE(next);
+ node->Next = n;
+ n = NODE(n)->Prev = next;
+ next = *(const CPpmd7_Node_Ref *)node;
+ node->Stamp = 0;
+ node->NU = (UInt16)nu;
+ }
+ }
+ NODE(head)->Stamp = 1;
+ NODE(head)->Next = n;
+ NODE(n)->Prev = head;
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd7_Node *)p->LoUnit)->Stamp = 1;
+
+ /* Glue free blocks */
+ while (n != head)
+ {
+ CPpmd7_Node *node = NODE(n);
+ UInt32 nu = (UInt32)node->NU;
+ for (;;)
+ {
+ CPpmd7_Node *node2 = NODE(n) + nu;
+ nu += node2->NU;
+ if (node2->Stamp != 0 || nu >= 0x10000)
+ break;
+ NODE(node2->Prev)->Next = node2->Next;
+ NODE(node2->Next)->Prev = node2->Prev;
+ node->NU = (UInt16)nu;
+ }
+ n = node->Next;
+ }
+
+ /* Fill lists of free blocks */
+ for (n = NODE(head)->Next; n != head;)
+ {
+ CPpmd7_Node *node = NODE(n);
+ unsigned nu;
+ CPpmd7_Node_Ref next = node->Next;
+ for (nu = node->NU; nu > 128; nu -= 128, node += 128)
+ InsertNode(p, node, PPMD_NUM_INDEXES - 1);
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, node + k, nu - k - 1);
+ }
+ InsertNode(p, node, i);
+ n = next;
+ }
+}
+
+static void *AllocUnitsRare(CPpmd7 *p, unsigned indx)
+{
+ unsigned i;
+ void *retVal;
+ if (p->GlueCount == 0)
+ {
+ GlueFreeBlocks(p);
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ }
+ i = indx;
+ do
+ {
+ if (++i == PPMD_NUM_INDEXES)
+ {
+ UInt32 numBytes = U2B(I2U(indx));
+ p->GlueCount--;
+ return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);
+ }
+ }
+ while (p->FreeList[i] == 0);
+ retVal = RemoveNode(p, i);
+ SplitBlock(p, retVal, i, indx);
+ return retVal;
+}
+
+static void *AllocUnits(CPpmd7 *p, unsigned indx)
+{
+ UInt32 numBytes;
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ numBytes = U2B(I2U(indx));
+ if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))
+ {
+ void *retVal = p->LoUnit;
+ p->LoUnit += numBytes;
+ return retVal;
+ }
+ return AllocUnitsRare(p, indx);
+}
+
+#define MyMem12Cpy(dest, src, num) \
+ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \
+ do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); }
+
+static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
+{
+ unsigned i0 = U2I(oldNU);
+ unsigned i1 = U2I(newNU);
+ if (i0 == i1)
+ return oldPtr;
+ if (p->FreeList[i1] != 0)
+ {
+ void *ptr = RemoveNode(p, i1);
+ MyMem12Cpy(ptr, oldPtr, newNU);
+ InsertNode(p, oldPtr, i0);
+ return ptr;
+ }
+ SplitBlock(p, oldPtr, i0, i1);
+ return oldPtr;
+}
+
+#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))
+
+static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
+{
+ (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);
+ (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
+}
+
+static void RestartModel(CPpmd7 *p)
+{
+ unsigned i, k, m;
+
+ memset(p->FreeList, 0, sizeof(p->FreeList));
+ p->Text = p->Base + p->AlignOffset;
+ p->HiUnit = p->Text + p->Size;
+ p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
+ p->GlueCount = 0;
+
+ p->OrderFall = p->MaxOrder;
+ p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
+ p->PrevSuccess = 0;
+
+ p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
+ p->MinContext->Suffix = 0;
+ p->MinContext->NumStats = 256;
+ p->MinContext->SummFreq = 256 + 1;
+ p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */
+ p->LoUnit += U2B(256 / 2);
+ p->MinContext->Stats = REF(p->FoundState);
+ for (i = 0; i < 256; i++)
+ {
+ CPpmd_State *s = &p->FoundState[i];
+ s->Symbol = (Byte)i;
+ s->Freq = 1;
+ SetSuccessor(s, 0);
+ }
+
+ for (i = 0; i < 128; i++)
+ for (k = 0; k < 8; k++)
+ {
+ UInt16 *dest = p->BinSumm[i] + k;
+ UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2));
+ for (m = 0; m < 64; m += 8)
+ dest[m] = val;
+ }
+
+ for (i = 0; i < 25; i++)
+ for (k = 0; k < 16; k++)
+ {
+ CPpmd_See *s = &p->See[i][k];
+ s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4));
+ s->Count = 4;
+ }
+}
+
+static void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder)
+{
+ p->MaxOrder = maxOrder;
+ RestartModel(p);
+ p->DummySee.Shift = PPMD_PERIOD_BITS;
+ p->DummySee.Summ = 0; /* unused */
+ p->DummySee.Count = 64; /* unused */
+}
+
+static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip)
+{
+ CPpmd_State upState;
+ CTX_PTR c = p->MinContext;
+ CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
+ CPpmd_State *ps[PPMD7_MAX_ORDER];
+ unsigned numPs = 0;
+
+ if (!skip)
+ ps[numPs++] = p->FoundState;
+
+ while (c->Suffix)
+ {
+ CPpmd_Void_Ref successor;
+ CPpmd_State *s;
+ c = SUFFIX(c);
+ if (c->NumStats != 1)
+ {
+ for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);
+ }
+ else
+ s = ONE_STATE(c);
+ successor = SUCCESSOR(s);
+ if (successor != upBranch)
+ {
+ c = CTX(successor);
+ if (numPs == 0)
+ return c;
+ break;
+ }
+ ps[numPs++] = s;
+ }
+
+ upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch);
+ SetSuccessor(&upState, upBranch + 1);
+
+ if (c->NumStats == 1)
+ upState.Freq = ONE_STATE(c)->Freq;
+ else
+ {
+ UInt32 cf, s0;
+ CPpmd_State *s;
+ for (s = STATS(c); s->Symbol != upState.Symbol; s++);
+ cf = s->Freq - 1;
+ s0 = c->SummFreq - c->NumStats - cf;
+ upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));
+ }
+
+ do
+ {
+ /* Create Child */
+ CTX_PTR c1; /* = AllocContext(p); */
+ if (p->HiUnit != p->LoUnit)
+ c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);
+ else if (p->FreeList[0] != 0)
+ c1 = (CTX_PTR)RemoveNode(p, 0);
+ else
+ {
+ c1 = (CTX_PTR)AllocUnitsRare(p, 0);
+ if (!c1)
+ return NULL;
+ }
+ c1->NumStats = 1;
+ *ONE_STATE(c1) = upState;
+ c1->Suffix = REF(c);
+ SetSuccessor(ps[--numPs], REF(c1));
+ c = c1;
+ }
+ while (numPs != 0);
+
+ return c;
+}
+
+static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
+{
+ CPpmd_State tmp = *t1;
+ *t1 = *t2;
+ *t2 = tmp;
+}
+
+static void UpdateModel(CPpmd7 *p)
+{
+ CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);
+ CTX_PTR c;
+ unsigned s0, ns;
+
+ if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
+ {
+ c = SUFFIX(p->MinContext);
+
+ if (c->NumStats == 1)
+ {
+ CPpmd_State *s = ONE_STATE(c);
+ if (s->Freq < 32)
+ s->Freq++;
+ }
+ else
+ {
+ CPpmd_State *s = STATS(c);
+ if (s->Symbol != p->FoundState->Symbol)
+ {
+ do { s++; } while (s->Symbol != p->FoundState->Symbol);
+ if (s[0].Freq >= s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ s--;
+ }
+ }
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq += 2;
+ c->SummFreq += 2;
+ }
+ }
+ }
+
+ if (p->OrderFall == 0)
+ {
+ p->MinContext = p->MaxContext = CreateSuccessors(p, True);
+ if (p->MinContext == 0)
+ {
+ RestartModel(p);
+ return;
+ }
+ SetSuccessor(p->FoundState, REF(p->MinContext));
+ return;
+ }
+
+ *p->Text++ = p->FoundState->Symbol;
+ successor = REF(p->Text);
+ if (p->Text >= p->UnitsStart)
+ {
+ RestartModel(p);
+ return;
+ }
+
+ if (fSuccessor)
+ {
+ if (fSuccessor <= successor)
+ {
+ CTX_PTR cs = CreateSuccessors(p, False);
+ if (cs == NULL)
+ {
+ RestartModel(p);
+ return;
+ }
+ fSuccessor = REF(cs);
+ }
+ if (--p->OrderFall == 0)
+ {
+ successor = fSuccessor;
+ p->Text -= (p->MaxContext != p->MinContext);
+ }
+ }
+ else
+ {
+ SetSuccessor(p->FoundState, successor);
+ fSuccessor = REF(p->MinContext);
+ }
+
+ s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1);
+
+ for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c))
+ {
+ unsigned ns1;
+ UInt32 cf, sf;
+ if ((ns1 = c->NumStats) != 1)
+ {
+ if ((ns1 & 1) == 0)
+ {
+ /* Expand for one UNIT */
+ unsigned oldNU = ns1 >> 1;
+ unsigned i = U2I(oldNU);
+ if (i != U2I(oldNU + 1))
+ {
+ void *ptr = AllocUnits(p, i + 1);
+ void *oldPtr;
+ if (!ptr)
+ {
+ RestartModel(p);
+ return;
+ }
+ oldPtr = STATS(c);
+ MyMem12Cpy(ptr, oldPtr, oldNU);
+ InsertNode(p, oldPtr, i);
+ c->Stats = STATS_REF(ptr);
+ }
+ }
+ c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1)));
+ }
+ else
+ {
+ CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);
+ if (!s)
+ {
+ RestartModel(p);
+ return;
+ }
+ *s = *ONE_STATE(c);
+ c->Stats = REF(s);
+ if (s->Freq < MAX_FREQ / 4 - 1)
+ s->Freq <<= 1;
+ else
+ s->Freq = MAX_FREQ - 4;
+ c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3));
+ }
+ cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6);
+ sf = (UInt32)s0 + c->SummFreq;
+ if (cf < 6 * sf)
+ {
+ cf = 1 + (cf > sf) + (cf >= 4 * sf);
+ c->SummFreq += 3;
+ }
+ else
+ {
+ cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);
+ c->SummFreq = (UInt16)(c->SummFreq + cf);
+ }
+ {
+ CPpmd_State *s = STATS(c) + ns1;
+ SetSuccessor(s, successor);
+ s->Symbol = p->FoundState->Symbol;
+ s->Freq = (Byte)cf;
+ c->NumStats = (UInt16)(ns1 + 1);
+ }
+ }
+ p->MaxContext = p->MinContext = CTX(fSuccessor);
+}
+
+static void Rescale(CPpmd7 *p)
+{
+ unsigned i, adder, sumFreq, escFreq;
+ CPpmd_State *stats = STATS(p->MinContext);
+ CPpmd_State *s = p->FoundState;
+ {
+ CPpmd_State tmp = *s;
+ for (; s != stats; s--)
+ s[0] = s[-1];
+ *s = tmp;
+ }
+ escFreq = p->MinContext->SummFreq - s->Freq;
+ s->Freq += 4;
+ adder = (p->OrderFall != 0);
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq = s->Freq;
+
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ escFreq -= (++s)->Freq;
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq += s->Freq;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ CPpmd_State *s1 = s;
+ CPpmd_State tmp = *s1;
+ do
+ s1[0] = s1[-1];
+ while (--s1 != stats && tmp.Freq > s1[-1].Freq);
+ *s1 = tmp;
+ }
+ }
+ while (--i);
+
+ if (s->Freq == 0)
+ {
+ unsigned numStats = p->MinContext->NumStats;
+ unsigned n0, n1;
+ do { i++; } while ((--s)->Freq == 0);
+ escFreq += i;
+ p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i);
+ if (p->MinContext->NumStats == 1)
+ {
+ CPpmd_State tmp = *stats;
+ do
+ {
+ tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1));
+ escFreq >>= 1;
+ }
+ while (escFreq > 1);
+ InsertNode(p, stats, U2I(((numStats + 1) >> 1)));
+ *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;
+ return;
+ }
+ n0 = (numStats + 1) >> 1;
+ n1 = (p->MinContext->NumStats + 1) >> 1;
+ if (n0 != n1)
+ p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
+ }
+ p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
+ p->FoundState = STATS(p->MinContext);
+}
+
+static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq)
+{
+ CPpmd_See *see;
+ unsigned nonMasked = p->MinContext->NumStats - numMasked;
+ if (p->MinContext->NumStats != 256)
+ {
+ see = p->See[p->NS2Indx[nonMasked - 1]] +
+ (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +
+ 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +
+ 4 * (numMasked > nonMasked) +
+ p->HiBitsFlag;
+ {
+ unsigned r = (see->Summ >> see->Shift);
+ see->Summ = (UInt16)(see->Summ - r);
+ *escFreq = r + (r == 0);
+ }
+ }
+ else
+ {
+ see = &p->DummySee;
+ *escFreq = 1;
+ }
+ return see;
+}
+
+static void NextContext(CPpmd7 *p)
+{
+ CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
+ if (p->OrderFall == 0 && (Byte *)c > p->Text)
+ p->MinContext = p->MaxContext = c;
+ else
+ UpdateModel(p);
+}
+
+static void Ppmd7_Update1(CPpmd7 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ s->Freq += 4;
+ p->MinContext->SummFreq += 4;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ p->FoundState = --s;
+ if (s->Freq > MAX_FREQ)
+ Rescale(p);
+ }
+ NextContext(p);
+}
+
+static void Ppmd7_Update1_0(CPpmd7 *p)
+{
+ p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq);
+ p->RunLength += p->PrevSuccess;
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ NextContext(p);
+}
+
+static void Ppmd7_UpdateBin(CPpmd7 *p)
+{
+ p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0));
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ NextContext(p);
+}
+
+static void Ppmd7_Update2(CPpmd7 *p)
+{
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ p->RunLength = p->InitRL;
+ UpdateModel(p);
+}
+
+/* ---------- Decode ---------- */
+
+static Bool Ppmd_RangeDec_Init(CPpmd7z_RangeDec *p)
+{
+ unsigned i;
+ p->Low = p->Bottom = 0;
+ p->Range = 0xFFFFFFFF;
+ for (i = 0; i < 4; i++)
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ return (p->Code < 0xFFFFFFFF);
+}
+
+static Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p)
+{
+ if (p->Stream->Read((void *)p->Stream) != 0)
+ return False;
+ return Ppmd_RangeDec_Init(p);
+}
+
+static Bool PpmdRAR_RangeDec_Init(CPpmd7z_RangeDec *p)
+{
+ if (!Ppmd_RangeDec_Init(p))
+ return False;
+ p->Bottom = 0x8000;
+ return True;
+}
+
+static UInt32 Range_GetThreshold(void *pp, UInt32 total)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ return (p->Code - p->Low) / (p->Range /= total);
+}
+
+static void Range_Normalize(CPpmd7z_RangeDec *p)
+{
+ while (1)
+ {
+ if((p->Low ^ (p->Low + p->Range)) >= kTopValue)
+ {
+ if(p->Range >= p->Bottom)
+ break;
+ else
+ p->Range = -p->Low & (p->Bottom - 1);
+ }
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ p->Range <<= 8;
+ p->Low <<= 8;
+ }
+}
+
+static void Range_Decode_7z(void *pp, UInt32 start, UInt32 size)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ p->Code -= start * p->Range;
+ p->Range *= size;
+ Range_Normalize(p);
+}
+
+static void Range_Decode_RAR(void *pp, UInt32 start, UInt32 size)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ p->Low += start * p->Range;
+ p->Range *= size;
+ Range_Normalize(p);
+}
+
+static UInt32 Range_DecodeBit_7z(void *pp, UInt32 size0)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ UInt32 newBound = (p->Range >> 14) * size0;
+ UInt32 symbol;
+ if (p->Code < newBound)
+ {
+ symbol = 0;
+ p->Range = newBound;
+ }
+ else
+ {
+ symbol = 1;
+ p->Code -= newBound;
+ p->Range -= newBound;
+ }
+ Range_Normalize(p);
+ return symbol;
+}
+
+static UInt32 Range_DecodeBit_RAR(void *pp, UInt32 size0)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ UInt32 bit, value = p->p.GetThreshold(p, PPMD_BIN_SCALE);
+ if(value < size0)
+ {
+ bit = 0;
+ p->p.Decode(p, 0, size0);
+ }
+ else
+ {
+ bit = 1;
+ p->p.Decode(p, size0, PPMD_BIN_SCALE - size0);
+ }
+ return bit;
+}
+
+static void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)
+{
+ p->p.GetThreshold = Range_GetThreshold;
+ p->p.Decode = Range_Decode_7z;
+ p->p.DecodeBit = Range_DecodeBit_7z;
+}
+
+static void PpmdRAR_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)
+{
+ p->p.GetThreshold = Range_GetThreshold;
+ p->p.Decode = Range_Decode_RAR;
+ p->p.DecodeBit = Range_DecodeBit_RAR;
+}
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+static int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 1)
+ {
+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
+ unsigned i;
+ UInt32 count, hiCnt;
+ if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq))
+ {
+ Byte symbol;
+ rc->Decode(rc, 0, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update1_0(p);
+ return symbol;
+ }
+ p->PrevSuccess = 0;
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ if ((hiCnt += (++s)->Freq) > count)
+ {
+ Byte symbol;
+ rc->Decode(rc, hiCnt - s->Freq, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update1(p);
+ return symbol;
+ }
+ }
+ while (--i);
+ if (count >= p->MinContext->SummFreq)
+ return -2;
+ p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
+ rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt);
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats - 1;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd7_GetBinSumm(p);
+ if (rc->DecodeBit(rc, *prob) == 0)
+ {
+ Byte symbol;
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
+ Ppmd7_UpdateBin(p);
+ return symbol;
+ }
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ for (;;)
+ {
+ CPpmd_State *ps[256], *s;
+ UInt32 freqSum, count, hiCnt;
+ CPpmd_See *see;
+ unsigned i, num, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return -1;
+ p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+ hiCnt = 0;
+ s = Ppmd7_GetStats(p, p->MinContext);
+ i = 0;
+ num = p->MinContext->NumStats - numMasked;
+ do
+ {
+ int k = (int)(MASK(s->Symbol));
+ hiCnt += (s->Freq & k);
+ ps[i] = s++;
+ i -= k;
+ }
+ while (i != num);
+
+ see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
+ freqSum += hiCnt;
+ count = rc->GetThreshold(rc, freqSum);
+
+ if (count < hiCnt)
+ {
+ Byte symbol;
+ CPpmd_State **pps = ps;
+ for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);
+ s = *pps;
+ rc->Decode(rc, hiCnt - s->Freq, s->Freq);
+ Ppmd_See_Update(see);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update2(p);
+ return symbol;
+ }
+ if (count >= freqSum)
+ return -2;
+ rc->Decode(rc, hiCnt, freqSum - hiCnt);
+ see->Summ = (UInt16)(see->Summ + freqSum);
+ do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);
+ }
+}
+
+/* ---------- Encode ---------- Ppmd7Enc.c */
+
+#define kTopValue (1 << 24)
+
+static void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p)
+{
+ p->Low = 0;
+ p->Range = 0xFFFFFFFF;
+ p->Cache = 0;
+ p->CacheSize = 1;
+}
+
+static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p)
+{
+ if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0)
+ {
+ Byte temp = p->Cache;
+ do
+ {
+ p->Stream->Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32)));
+ temp = 0xFF;
+ }
+ while(--p->CacheSize != 0);
+ p->Cache = (Byte)((UInt32)p->Low >> 24);
+ }
+ p->CacheSize++;
+ p->Low = (UInt32)p->Low << 8;
+}
+
+static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total)
+{
+ p->Low += start * (p->Range /= total);
+ p->Range *= size;
+ while (p->Range < kTopValue)
+ {
+ p->Range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0)
+{
+ p->Range = (p->Range >> 14) * size0;
+ while (p->Range < kTopValue)
+ {
+ p->Range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0)
+{
+ UInt32 newBound = (p->Range >> 14) * size0;
+ p->Low += newBound;
+ p->Range -= newBound;
+ while (p->Range < kTopValue)
+ {
+ p->Range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+static void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p)
+{
+ unsigned i;
+ for (i = 0; i < 5; i++)
+ RangeEnc_ShiftLow(p);
+}
+
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+static void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 1)
+ {
+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
+ UInt32 sum;
+ unsigned i;
+ if (s->Symbol == symbol)
+ {
+ RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq);
+ p->FoundState = s;
+ Ppmd7_Update1_0(p);
+ return;
+ }
+ p->PrevSuccess = 0;
+ sum = s->Freq;
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ if ((++s)->Symbol == symbol)
+ {
+ RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq);
+ p->FoundState = s;
+ Ppmd7_Update1(p);
+ return;
+ }
+ sum += s->Freq;
+ }
+ while (--i);
+
+ p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats - 1;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd7_GetBinSumm(p);
+ CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
+ if (s->Symbol == symbol)
+ {
+ RangeEnc_EncodeBit_0(rc, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ p->FoundState = s;
+ Ppmd7_UpdateBin(p);
+ return;
+ }
+ else
+ {
+ RangeEnc_EncodeBit_1(rc, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ }
+ for (;;)
+ {
+ UInt32 escFreq;
+ CPpmd_See *see;
+ CPpmd_State *s;
+ UInt32 sum;
+ unsigned i, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return; /* EndMarker (symbol = -1) */
+ p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+
+ see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq);
+ s = Ppmd7_GetStats(p, p->MinContext);
+ sum = 0;
+ i = p->MinContext->NumStats;
+ do
+ {
+ int cur = s->Symbol;
+ if (cur == symbol)
+ {
+ UInt32 low = sum;
+ CPpmd_State *s1 = s;
+ do
+ {
+ sum += (s->Freq & (int)(MASK(s->Symbol)));
+ s++;
+ }
+ while (--i);
+ RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq);
+ Ppmd_See_Update(see);
+ p->FoundState = s1;
+ Ppmd7_Update2(p);
+ return;
+ }
+ sum += (s->Freq & (int)(MASK(cur)));
+ MASK(cur) = 0;
+ s++;
+ }
+ while (--i);
+
+ RangeEnc_Encode(rc, sum, escFreq, sum + escFreq);
+ see->Summ = (UInt16)(see->Summ + sum + escFreq);
+ }
+}
+
+const IPpmd7 __archive_ppmd7_functions =
+{
+ &Ppmd7_Construct,
+ &Ppmd7_Alloc,
+ &Ppmd7_Free,
+ &Ppmd7_Init,
+ &Ppmd7z_RangeDec_CreateVTable,
+ &PpmdRAR_RangeDec_CreateVTable,
+ &Ppmd7z_RangeDec_Init,
+ &PpmdRAR_RangeDec_Init,
+ &Ppmd7_DecodeSymbol,
+ &Ppmd7z_RangeEnc_Init,
+ &Ppmd7z_RangeEnc_FlushData,
+ &Ppmd7_EncodeSymbol
+};
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_ppmd7_private.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_ppmd7_private.h Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,119 @@
+/* Ppmd7.h -- PPMdH compression codec
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+/* This code supports virtual RangeDecoder and includes the implementation
+of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H.
+If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_PPMD7_PRIVATE_H_INCLUDED
+#define ARCHIVE_PPMD7_PRIVATE_H_INCLUDED
+
+#include "archive_ppmd_private.h"
+
+#define PPMD7_MIN_ORDER 2
+#define PPMD7_MAX_ORDER 64
+
+#define PPMD7_MIN_MEM_SIZE (1 << 11)
+#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
+
+struct CPpmd7_Context_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd7_Context_ *
+ #else
+ UInt32
+ #endif
+ CPpmd7_Context_Ref;
+
+typedef struct CPpmd7_Context_
+{
+ UInt16 NumStats;
+ UInt16 SummFreq;
+ CPpmd_State_Ref Stats;
+ CPpmd7_Context_Ref Suffix;
+} CPpmd7_Context;
+
+#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
+
+typedef struct
+{
+ CPpmd7_Context *MinContext, *MaxContext;
+ CPpmd_State *FoundState;
+ unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag;
+ Int32 RunLength, InitRL; /* must be 32-bit at least */
+
+ UInt32 Size;
+ UInt32 GlueCount;
+ Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
+ UInt32 AlignOffset;
+
+ Byte Indx2Units[PPMD_NUM_INDEXES];
+ Byte Units2Indx[128];
+ CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
+ Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
+ CPpmd_See DummySee, See[25][16];
+ UInt16 BinSumm[128][64];
+} CPpmd7;
+
+/* ---------- Decode ---------- */
+
+typedef struct
+{
+ UInt32 (*GetThreshold)(void *p, UInt32 total);
+ void (*Decode)(void *p, UInt32 start, UInt32 size);
+ UInt32 (*DecodeBit)(void *p, UInt32 size0);
+} IPpmd7_RangeDec;
+
+typedef struct
+{
+ IPpmd7_RangeDec p;
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 Low;
+ UInt32 Bottom;
+ IByteIn *Stream;
+} CPpmd7z_RangeDec;
+
+/* ---------- Encode ---------- */
+
+typedef struct
+{
+ UInt64 Low;
+ UInt32 Range;
+ Byte Cache;
+ UInt64 CacheSize;
+ IByteOut *Stream;
+} CPpmd7z_RangeEnc;
+
+typedef struct
+{
+ /* Base Functions */
+ void (*Ppmd7_Construct)(CPpmd7 *p);
+ Bool (*Ppmd7_Alloc)(CPpmd7 *p, UInt32 size, ISzAlloc *alloc);
+ void (*Ppmd7_Free)(CPpmd7 *p, ISzAlloc *alloc);
+ void (*Ppmd7_Init)(CPpmd7 *p, unsigned maxOrder);
+ #define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
+
+ /* Decode Functions */
+ void (*Ppmd7z_RangeDec_CreateVTable)(CPpmd7z_RangeDec *p);
+ void (*PpmdRAR_RangeDec_CreateVTable)(CPpmd7z_RangeDec *p);
+ Bool (*Ppmd7z_RangeDec_Init)(CPpmd7z_RangeDec *p);
+ Bool (*PpmdRAR_RangeDec_Init)(CPpmd7z_RangeDec *p);
+ #define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
+ int (*Ppmd7_DecodeSymbol)(CPpmd7 *p, IPpmd7_RangeDec *rc);
+
+ /* Encode Functions */
+ void (*Ppmd7z_RangeEnc_Init)(CPpmd7z_RangeEnc *p);
+ void (*Ppmd7z_RangeEnc_FlushData)(CPpmd7z_RangeEnc *p);
+
+ void (*Ppmd7_EncodeSymbol)(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol);
+} IPpmd7;
+
+extern const IPpmd7 __archive_ppmd7_functions;
+#endif
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_ppmd_private.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_ppmd_private.h Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,158 @@
+/* Ppmd.h -- PPMD codec common code
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_PPMD_PRIVATE_H_INCLUDED
+#define ARCHIVE_PPMD_PRIVATE_H_INCLUDED
+
+#include <stddef.h>
+
+#include "archive_read_private.h"
+
+/*** Begin defined in Types.h ***/
+
+#if !defined(ZCONF_H)
+typedef unsigned char Byte;
+#endif
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef long Int32;
+typedef unsigned long UInt32;
+#else
+typedef int Int32;
+typedef unsigned int UInt32;
+#endif
+
+#ifdef _SZ_NO_INT_64
+
+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
+ NOTES: Some code will work incorrectly in that case! */
+
+typedef long Int64;
+typedef unsigned long UInt64;
+
+#else
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#define UINT64_CONST(n) n
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#define UINT64_CONST(n) n ## ULL
+#endif
+
+#endif
+
+typedef int Bool;
+#define True 1
+#define False 0
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct
+{
+ struct archive_read *a;
+ Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
+} IByteIn;
+
+typedef struct
+{
+ struct archive_write *a;
+ void (*Write)(void *p, Byte b);
+} IByteOut;
+
+
+typedef struct
+{
+ void *(*Alloc)(void *p, size_t size);
+ void (*Free)(void *p, void *address); /* address can be 0 */
+} ISzAlloc;
+
+/*** End defined in Types.h ***/
+/*** Begin defined in CpuArch.h ***/
+
+#if defined(_M_IX86) || defined(__i386__)
+#define MY_CPU_X86
+#endif
+
+#if defined(MY_CPU_X86) || defined(_M_ARM)
+#define MY_CPU_32BIT
+#endif
+
+#ifdef MY_CPU_32BIT
+#define PPMD_32BIT
+#endif
+
+/*** End defined in CpuArch.h ***/
+
+#define PPMD_INT_BITS 7
+#define PPMD_PERIOD_BITS 7
+#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))
+
+#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))
+#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)
+#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))
+#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))
+
+#define PPMD_N1 4
+#define PPMD_N2 4
+#define PPMD_N3 4
+#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)
+#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)
+
+/* SEE-contexts for PPM-contexts with masked symbols */
+typedef struct
+{
+ UInt16 Summ; /* Freq */
+ Byte Shift; /* Speed of Freq change; low Shift is for fast change */
+ Byte Count; /* Count to next change of Shift */
+} CPpmd_See;
+
+#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \
+ { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); }
+
+typedef struct
+{
+ Byte Symbol;
+ Byte Freq;
+ UInt16 SuccessorLow;
+ UInt16 SuccessorHigh;
+} CPpmd_State;
+
+typedef
+ #ifdef PPMD_32BIT
+ CPpmd_State *
+ #else
+ UInt32
+ #endif
+ CPpmd_State_Ref;
+
+typedef
+ #ifdef PPMD_32BIT
+ void *
+ #else
+ UInt32
+ #endif
+ CPpmd_Void_Ref;
+
+typedef
+ #ifdef PPMD_32BIT
+ Byte *
+ #else
+ UInt32
+ #endif
+ CPpmd_Byte_Ref;
+
+#define PPMD_SetAllBitsIn256Bytes(p) \
+ { unsigned j; for (j = 0; j < 256 / sizeof(p[0]); j += 8) { \
+ p[j+7] = p[j+6] = p[j+5] = p[j+4] = p[j+3] = p[j+2] = p[j+1] = p[j+0] = ~(size_t)0; }}
+
+#endif
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_rb.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_rb.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,701 @@
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas <matt at 3am-software.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Based on: NetBSD: rb.c,v 1.6 2010/04/30 13:58:09 joerg Exp
+ */
+
+#include "archive_platform.h"
+
+#include <stddef.h>
+
+#include "archive_rb.h"
+
+/* Keep in sync with archive_rb.h */
+#define RB_DIR_LEFT 0
+#define RB_DIR_RIGHT 1
+#define RB_DIR_OTHER 1
+#define rb_left rb_nodes[RB_DIR_LEFT]
+#define rb_right rb_nodes[RB_DIR_RIGHT]
+
+#define RB_FLAG_POSITION 0x2
+#define RB_FLAG_RED 0x1
+#define RB_FLAG_MASK (RB_FLAG_POSITION|RB_FLAG_RED)
+#define RB_FATHER(rb) \
+ ((struct archive_rb_node *)((rb)->rb_info & ~RB_FLAG_MASK))
+#define RB_SET_FATHER(rb, father) \
+ ((void)((rb)->rb_info = (uintptr_t)(father)|((rb)->rb_info & RB_FLAG_MASK)))
+
+#define RB_SENTINEL_P(rb) ((rb) == NULL)
+#define RB_LEFT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_left)
+#define RB_RIGHT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_right)
+#define RB_FATHER_SENTINEL_P(rb) RB_SENTINEL_P(RB_FATHER((rb)))
+#define RB_CHILDLESS_P(rb) \
+ (RB_SENTINEL_P(rb) || (RB_LEFT_SENTINEL_P(rb) && RB_RIGHT_SENTINEL_P(rb)))
+#define RB_TWOCHILDREN_P(rb) \
+ (!RB_SENTINEL_P(rb) && !RB_LEFT_SENTINEL_P(rb) && !RB_RIGHT_SENTINEL_P(rb))
+
+#define RB_POSITION(rb) \
+ (((rb)->rb_info & RB_FLAG_POSITION) ? RB_DIR_RIGHT : RB_DIR_LEFT)
+#define RB_RIGHT_P(rb) (RB_POSITION(rb) == RB_DIR_RIGHT)
+#define RB_LEFT_P(rb) (RB_POSITION(rb) == RB_DIR_LEFT)
+#define RB_RED_P(rb) (!RB_SENTINEL_P(rb) && ((rb)->rb_info & RB_FLAG_RED) != 0)
+#define RB_BLACK_P(rb) (RB_SENTINEL_P(rb) || ((rb)->rb_info & RB_FLAG_RED) == 0)
+#define RB_MARK_RED(rb) ((void)((rb)->rb_info |= RB_FLAG_RED))
+#define RB_MARK_BLACK(rb) ((void)((rb)->rb_info &= ~RB_FLAG_RED))
+#define RB_INVERT_COLOR(rb) ((void)((rb)->rb_info ^= RB_FLAG_RED))
+#define RB_ROOT_P(rbt, rb) ((rbt)->rbt_root == (rb))
+#define RB_SET_POSITION(rb, position) \
+ ((void)((position) ? ((rb)->rb_info |= RB_FLAG_POSITION) : \
+ ((rb)->rb_info &= ~RB_FLAG_POSITION)))
+#define RB_ZERO_PROPERTIES(rb) ((void)((rb)->rb_info &= ~RB_FLAG_MASK))
+#define RB_COPY_PROPERTIES(dst, src) \
+ ((void)((dst)->rb_info ^= ((dst)->rb_info ^ (src)->rb_info) & RB_FLAG_MASK))
+#define RB_SWAP_PROPERTIES(a, b) do { \
+ uintptr_t xorinfo = ((a)->rb_info ^ (b)->rb_info) & RB_FLAG_MASK; \
+ (a)->rb_info ^= xorinfo; \
+ (b)->rb_info ^= xorinfo; \
+ } while (/*CONSTCOND*/ 0)
+
+static void __archive_rb_tree_insert_rebalance(struct archive_rb_tree *,
+ struct archive_rb_node *);
+static void __archive_rb_tree_removal_rebalance(struct archive_rb_tree *,
+ struct archive_rb_node *, unsigned int);
+
+#define RB_SENTINEL_NODE NULL
+
+#define T 1
+#define F 0
+
+void
+__archive_rb_tree_init(struct archive_rb_tree *rbt,
+ const struct archive_rb_tree_ops *ops)
+{
+ rbt->rbt_ops = ops;
+ *((struct archive_rb_node **)&rbt->rbt_root) = RB_SENTINEL_NODE;
+}
+
+struct archive_rb_node *
+__archive_rb_tree_find_node(struct archive_rb_tree *rbt, const void *key)
+{
+ archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;
+ struct archive_rb_node *parent = rbt->rbt_root;
+
+ while (!RB_SENTINEL_P(parent)) {
+ const signed int diff = (*compare_key)(parent, key);
+ if (diff == 0)
+ return parent;
+ parent = parent->rb_nodes[diff > 0];
+ }
+
+ return NULL;
+}
+
+struct archive_rb_node *
+__archive_rb_tree_find_node_geq(struct archive_rb_tree *rbt, const void *key)
+{
+ archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;
+ struct archive_rb_node *parent = rbt->rbt_root;
+ struct archive_rb_node *last = NULL;
+
+ while (!RB_SENTINEL_P(parent)) {
+ const signed int diff = (*compare_key)(parent, key);
+ if (diff == 0)
+ return parent;
+ if (diff < 0)
+ last = parent;
+ parent = parent->rb_nodes[diff > 0];
+ }
+
+ return last;
+}
+
+struct archive_rb_node *
+__archive_rb_tree_find_node_leq(struct archive_rb_tree *rbt, const void *key)
+{
+ archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;
+ struct archive_rb_node *parent = rbt->rbt_root;
+ struct archive_rb_node *last = NULL;
+
+ while (!RB_SENTINEL_P(parent)) {
+ const signed int diff = (*compare_key)(parent, key);
+ if (diff == 0)
+ return parent;
+ if (diff > 0)
+ last = parent;
+ parent = parent->rb_nodes[diff > 0];
+ }
+
+ return last;
+}
+
+int
+__archive_rb_tree_insert_node(struct archive_rb_tree *rbt,
+ struct archive_rb_node *self)
+{
+ archive_rbto_compare_nodes_fn compare_nodes = rbt->rbt_ops->rbto_compare_nodes;
+ struct archive_rb_node *parent, *tmp;
+ unsigned int position;
+ int rebalance;
+
+ tmp = rbt->rbt_root;
+ /*
+ * This is a hack. Because rbt->rbt_root is just a
+ * struct archive_rb_node *, just like rb_node->rb_nodes[RB_DIR_LEFT],
+ * we can use this fact to avoid a lot of tests for root and know
+ * that even at root, updating
+ * RB_FATHER(rb_node)->rb_nodes[RB_POSITION(rb_node)] will
+ * update rbt->rbt_root.
+ */
+ parent = (struct archive_rb_node *)(void *)&rbt->rbt_root;
+ position = RB_DIR_LEFT;
+
+ /*
+ * Find out where to place this new leaf.
+ */
+ while (!RB_SENTINEL_P(tmp)) {
+ const signed int diff = (*compare_nodes)(tmp, self);
+ if (diff == 0) {
+ /*
+ * Node already exists; don't insert.
+ */
+ return F;
+ }
+ parent = tmp;
+ position = (diff > 0);
+ tmp = parent->rb_nodes[position];
+ }
+
+ /*
+ * Initialize the node and insert as a leaf into the tree.
+ */
+ RB_SET_FATHER(self, parent);
+ RB_SET_POSITION(self, position);
+ if (parent == (struct archive_rb_node *)(void *)&rbt->rbt_root) {
+ RB_MARK_BLACK(self); /* root is always black */
+ rebalance = F;
+ } else {
+ /*
+ * All new nodes are colored red. We only need to rebalance
+ * if our parent is also red.
+ */
+ RB_MARK_RED(self);
+ rebalance = RB_RED_P(parent);
+ }
+ self->rb_left = parent->rb_nodes[position];
+ self->rb_right = parent->rb_nodes[position];
+ parent->rb_nodes[position] = self;
+
+ /*
+ * Rebalance tree after insertion
+ */
+ if (rebalance)
+ __archive_rb_tree_insert_rebalance(rbt, self);
+
+ return T;
+}
+
+/*
+ * Swap the location and colors of 'self' and its child @ which. The child
+ * can not be a sentinel node. This is our rotation function. However,
+ * since it preserves coloring, it great simplifies both insertion and
+ * removal since rotation almost always involves the exchanging of colors
+ * as a separate step.
+ */
+/*ARGSUSED*/
+static void
+__archive_rb_tree_reparent_nodes(
+ struct archive_rb_node *old_father, const unsigned int which)
+{
+ const unsigned int other = which ^ RB_DIR_OTHER;
+ struct archive_rb_node * const grandpa = RB_FATHER(old_father);
+ struct archive_rb_node * const old_child = old_father->rb_nodes[which];
+ struct archive_rb_node * const new_father = old_child;
+ struct archive_rb_node * const new_child = old_father;
+
+ /*
+ * Exchange descendant linkages.
+ */
+ grandpa->rb_nodes[RB_POSITION(old_father)] = new_father;
+ new_child->rb_nodes[which] = old_child->rb_nodes[other];
+ new_father->rb_nodes[other] = new_child;
+
+ /*
+ * Update ancestor linkages
+ */
+ RB_SET_FATHER(new_father, grandpa);
+ RB_SET_FATHER(new_child, new_father);
+
+ /*
+ * Exchange properties between new_father and new_child. The only
+ * change is that new_child's position is now on the other side.
+ */
+ RB_SWAP_PROPERTIES(new_father, new_child);
+ RB_SET_POSITION(new_child, other);
+
+ /*
+ * Make sure to reparent the new child to ourself.
+ */
+ if (!RB_SENTINEL_P(new_child->rb_nodes[which])) {
+ RB_SET_FATHER(new_child->rb_nodes[which], new_child);
+ RB_SET_POSITION(new_child->rb_nodes[which], which);
+ }
+
+}
+
+static void
+__archive_rb_tree_insert_rebalance(struct archive_rb_tree *rbt,
+ struct archive_rb_node *self)
+{
+ struct archive_rb_node * father = RB_FATHER(self);
+ struct archive_rb_node * grandpa;
+ struct archive_rb_node * uncle;
+ unsigned int which;
+ unsigned int other;
+
+ for (;;) {
+ /*
+ * We are red and our parent is red, therefore we must have a
+ * grandfather and he must be black.
+ */
+ grandpa = RB_FATHER(father);
+ which = (father == grandpa->rb_right);
+ other = which ^ RB_DIR_OTHER;
+ uncle = grandpa->rb_nodes[other];
+
+ if (RB_BLACK_P(uncle))
+ break;
+
+ /*
+ * Case 1: our uncle is red
+ * Simply invert the colors of our parent and
+ * uncle and make our grandparent red. And
+ * then solve the problem up at his level.
+ */
+ RB_MARK_BLACK(uncle);
+ RB_MARK_BLACK(father);
+ if (RB_ROOT_P(rbt, grandpa)) {
+ /*
+ * If our grandpa is root, don't bother
+ * setting him to red, just return.
+ */
+ return;
+ }
+ RB_MARK_RED(grandpa);
+ self = grandpa;
+ father = RB_FATHER(self);
+ if (RB_BLACK_P(father)) {
+ /*
+ * If our greatgrandpa is black, we're done.
+ */
+ return;
+ }
+ }
+
+ /*
+ * Case 2&3: our uncle is black.
+ */
+ if (self == father->rb_nodes[other]) {
+ /*
+ * Case 2: we are on the same side as our uncle
+ * Swap ourselves with our parent so this case
+ * becomes case 3. Basically our parent becomes our
+ * child.
+ */
+ __archive_rb_tree_reparent_nodes(father, other);
+ }
+ /*
+ * Case 3: we are opposite a child of a black uncle.
+ * Swap our parent and grandparent. Since our grandfather
+ * is black, our father will become black and our new sibling
+ * (former grandparent) will become red.
+ */
+ __archive_rb_tree_reparent_nodes(grandpa, which);
+
+ /*
+ * Final step: Set the root to black.
+ */
+ RB_MARK_BLACK(rbt->rbt_root);
+}
+
+static void
+__archive_rb_tree_prune_node(struct archive_rb_tree *rbt,
+ struct archive_rb_node *self, int rebalance)
+{
+ const unsigned int which = RB_POSITION(self);
+ struct archive_rb_node *father = RB_FATHER(self);
+
+ /*
+ * Since we are childless, we know that self->rb_left is pointing
+ * to the sentinel node.
+ */
+ father->rb_nodes[which] = self->rb_left;
+
+ /*
+ * Rebalance if requested.
+ */
+ if (rebalance)
+ __archive_rb_tree_removal_rebalance(rbt, father, which);
+}
+
+/*
+ * When deleting an interior node
+ */
+static void
+__archive_rb_tree_swap_prune_and_rebalance(struct archive_rb_tree *rbt,
+ struct archive_rb_node *self, struct archive_rb_node *standin)
+{
+ const unsigned int standin_which = RB_POSITION(standin);
+ unsigned int standin_other = standin_which ^ RB_DIR_OTHER;
+ struct archive_rb_node *standin_son;
+ struct archive_rb_node *standin_father = RB_FATHER(standin);
+ int rebalance = RB_BLACK_P(standin);
+
+ if (standin_father == self) {
+ /*
+ * As a child of self, any children would be opposite of
+ * our parent.
+ */
+ standin_son = standin->rb_nodes[standin_which];
+ } else {
+ /*
+ * Since we aren't a child of self, any children would be
+ * on the same side as our parent.
+ */
+ standin_son = standin->rb_nodes[standin_other];
+ }
+
+ if (RB_RED_P(standin_son)) {
+ /*
+ * We know we have a red child so if we flip it to black
+ * we don't have to rebalance.
+ */
+ RB_MARK_BLACK(standin_son);
+ rebalance = F;
+
+ if (standin_father != self) {
+ /*
+ * Change the son's parentage to point to his grandpa.
+ */
+ RB_SET_FATHER(standin_son, standin_father);
+ RB_SET_POSITION(standin_son, standin_which);
+ }
+ }
+
+ if (standin_father == self) {
+ /*
+ * If we are about to delete the standin's father, then when
+ * we call rebalance, we need to use ourselves as our father.
+ * Otherwise remember our original father. Also, since we are
+ * our standin's father we only need to reparent the standin's
+ * brother.
+ *
+ * | R --> S |
+ * | Q S --> Q T |
+ * | t --> |
+ *
+ * Have our son/standin adopt his brother as his new son.
+ */
+ standin_father = standin;
+ } else {
+ /*
+ * | R --> S . |
+ * | / \ | T --> / \ | / |
+ * | ..... | S --> ..... | T |
+ *
+ * Sever standin's connection to his father.
+ */
+ standin_father->rb_nodes[standin_which] = standin_son;
+ /*
+ * Adopt the far son.
+ */
+ standin->rb_nodes[standin_other] = self->rb_nodes[standin_other];
+ RB_SET_FATHER(standin->rb_nodes[standin_other], standin);
+ /*
+ * Use standin_other because we need to preserve standin_which
+ * for the removal_rebalance.
+ */
+ standin_other = standin_which;
+ }
+
+ /*
+ * Move the only remaining son to our standin. If our standin is our
+ * son, this will be the only son needed to be moved.
+ */
+ standin->rb_nodes[standin_other] = self->rb_nodes[standin_other];
+ RB_SET_FATHER(standin->rb_nodes[standin_other], standin);
+
+ /*
+ * Now copy the result of self to standin and then replace
+ * self with standin in the tree.
+ */
+ RB_COPY_PROPERTIES(standin, self);
+ RB_SET_FATHER(standin, RB_FATHER(self));
+ RB_FATHER(standin)->rb_nodes[RB_POSITION(standin)] = standin;
+
+ if (rebalance)
+ __archive_rb_tree_removal_rebalance(rbt, standin_father, standin_which);
+}
+
+/*
+ * We could do this by doing
+ * __archive_rb_tree_node_swap(rbt, self, which);
+ * __archive_rb_tree_prune_node(rbt, self, F);
+ *
+ * But it's more efficient to just evaluate and recolor the child.
+ */
+static void
+__archive_rb_tree_prune_blackred_branch(
+ struct archive_rb_node *self, unsigned int which)
+{
+ struct archive_rb_node *father = RB_FATHER(self);
+ struct archive_rb_node *son = self->rb_nodes[which];
+
+ /*
+ * Remove ourselves from the tree and give our former child our
+ * properties (position, color, root).
+ */
+ RB_COPY_PROPERTIES(son, self);
+ father->rb_nodes[RB_POSITION(son)] = son;
+ RB_SET_FATHER(son, father);
+}
+/*
+ *
+ */
+void
+__archive_rb_tree_remove_node(struct archive_rb_tree *rbt,
+ struct archive_rb_node *self)
+{
+ struct archive_rb_node *standin;
+ unsigned int which;
+
+ /*
+ * In the following diagrams, we (the node to be removed) are S. Red
+ * nodes are lowercase. T could be either red or black.
+ *
+ * Remember the major axiom of the red-black tree: the number of
+ * black nodes from the root to each leaf is constant across all
+ * leaves, only the number of red nodes varies.
+ *
+ * Thus removing a red leaf doesn't require any other changes to a
+ * red-black tree. So if we must remove a node, attempt to rearrange
+ * the tree so we can remove a red node.
+ *
+ * The simplest case is a childless red node or a childless root node:
+ *
+ * | T --> T | or | R --> * |
+ * | s --> * |
+ */
+ if (RB_CHILDLESS_P(self)) {
+ const int rebalance = RB_BLACK_P(self) && !RB_ROOT_P(rbt, self);
+ __archive_rb_tree_prune_node(rbt, self, rebalance);
+ return;
+ }
+ if (!RB_TWOCHILDREN_P(self)) {
+ /*
+ * The next simplest case is the node we are deleting is
+ * black and has one red child.
+ *
+ * | T --> T --> T |
+ * | S --> R --> R |
+ * | r --> s --> * |
+ */
+ which = RB_LEFT_SENTINEL_P(self) ? RB_DIR_RIGHT : RB_DIR_LEFT;
+ __archive_rb_tree_prune_blackred_branch(self, which);
+ return;
+ }
+
+ /*
+ * We invert these because we prefer to remove from the inside of
+ * the tree.
+ */
+ which = RB_POSITION(self) ^ RB_DIR_OTHER;
+
+ /*
+ * Let's find the node closes to us opposite of our parent
+ * Now swap it with ourself, "prune" it, and rebalance, if needed.
+ */
+ standin = __archive_rb_tree_iterate(rbt, self, which);
+ __archive_rb_tree_swap_prune_and_rebalance(rbt, self, standin);
+}
+
+static void
+__archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt,
+ struct archive_rb_node *parent, unsigned int which)
+{
+
+ while (RB_BLACK_P(parent->rb_nodes[which])) {
+ unsigned int other = which ^ RB_DIR_OTHER;
+ struct archive_rb_node *brother = parent->rb_nodes[other];
+
+ /*
+ * For cases 1, 2a, and 2b, our brother's children must
+ * be black and our father must be black
+ */
+ if (RB_BLACK_P(parent)
+ && RB_BLACK_P(brother->rb_left)
+ && RB_BLACK_P(brother->rb_right)) {
+ if (RB_RED_P(brother)) {
+ /*
+ * Case 1: Our brother is red, swap its
+ * position (and colors) with our parent.
+ * This should now be case 2b (unless C or E
+ * has a red child which is case 3; thus no
+ * explicit branch to case 2b).
+ *
+ * B -> D
+ * A d -> b E
+ * C E -> A C
+ */
+ __archive_rb_tree_reparent_nodes(parent, other);
+ brother = parent->rb_nodes[other];
+ } else {
+ /*
+ * Both our parent and brother are black.
+ * Change our brother to red, advance up rank
+ * and go through the loop again.
+ *
+ * B -> *B
+ * *A D -> A d
+ * C E -> C E
+ */
+ RB_MARK_RED(brother);
+ if (RB_ROOT_P(rbt, parent))
+ return; /* root == parent == black */
+ which = RB_POSITION(parent);
+ parent = RB_FATHER(parent);
+ continue;
+ }
+ }
+ /*
+ * Avoid an else here so that case 2a above can hit either
+ * case 2b, 3, or 4.
+ */
+ if (RB_RED_P(parent)
+ && RB_BLACK_P(brother)
+ && RB_BLACK_P(brother->rb_left)
+ && RB_BLACK_P(brother->rb_right)) {
+ /*
+ * We are black, our father is red, our brother and
+ * both nephews are black. Simply invert/exchange the
+ * colors of our father and brother (to black and red
+ * respectively).
+ *
+ * | f --> F |
+ * | * B --> * b |
+ * | N N --> N N |
+ */
+ RB_MARK_BLACK(parent);
+ RB_MARK_RED(brother);
+ break; /* We're done! */
+ } else {
+ /*
+ * Our brother must be black and have at least one
+ * red child (it may have two).
+ */
+ if (RB_BLACK_P(brother->rb_nodes[other])) {
+ /*
+ * Case 3: our brother is black, our near
+ * nephew is red, and our far nephew is black.
+ * Swap our brother with our near nephew.
+ * This result in a tree that matches case 4.
+ * (Our father could be red or black).
+ *
+ * | F --> F |
+ * | x B --> x B |
+ * | n --> n |
+ */
+ __archive_rb_tree_reparent_nodes(brother, which);
+ brother = parent->rb_nodes[other];
+ }
+ /*
+ * Case 4: our brother is black and our far nephew
+ * is red. Swap our father and brother locations and
+ * change our far nephew to black. (these can be
+ * done in either order so we change the color first).
+ * The result is a valid red-black tree and is a
+ * terminal case. (again we don't care about the
+ * father's color)
+ *
+ * If the father is red, we will get a red-black-black
+ * tree:
+ * | f -> f --> b |
+ * | B -> B --> F N |
+ * | n -> N --> |
+ *
+ * If the father is black, we will get an all black
+ * tree:
+ * | F -> F --> B |
+ * | B -> B --> F N |
+ * | n -> N --> |
+ *
+ * If we had two red nephews, then after the swap,
+ * our former father would have a red grandson.
+ */
+ RB_MARK_BLACK(brother->rb_nodes[other]);
+ __archive_rb_tree_reparent_nodes(parent, other);
+ break; /* We're done! */
+ }
+ }
+}
+
+struct archive_rb_node *
+__archive_rb_tree_iterate(struct archive_rb_tree *rbt,
+ struct archive_rb_node *self, const unsigned int direction)
+{
+ const unsigned int other = direction ^ RB_DIR_OTHER;
+
+ if (self == NULL) {
+ self = rbt->rbt_root;
+ if (RB_SENTINEL_P(self))
+ return NULL;
+ while (!RB_SENTINEL_P(self->rb_nodes[direction]))
+ self = self->rb_nodes[direction];
+ return self;
+ }
+ /*
+ * We can't go any further in this direction. We proceed up in the
+ * opposite direction until our parent is in direction we want to go.
+ */
+ if (RB_SENTINEL_P(self->rb_nodes[direction])) {
+ while (!RB_ROOT_P(rbt, self)) {
+ if (other == (unsigned int)RB_POSITION(self))
+ return RB_FATHER(self);
+ self = RB_FATHER(self);
+ }
+ return NULL;
+ }
+
+ /*
+ * Advance down one in current direction and go down as far as possible
+ * in the opposite direction.
+ */
+ self = self->rb_nodes[direction];
+ while (!RB_SENTINEL_P(self->rb_nodes[other]))
+ self = self->rb_nodes[other];
+ return self;
+}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_rb.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_rb.h Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas <matt at 3am-software.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Based on NetBSD: rb.h,v 1.13 2009/08/16 10:57:01 yamt Exp
+ */
+#ifndef ARCHIVE_RB_H_
+#define ARCHIVE_RB_H_
+
+struct archive_rb_node {
+ struct archive_rb_node *rb_nodes[2];
+ /*
+ * rb_info contains the two flags and the parent back pointer.
+ * We put the two flags in the low two bits since we know that
+ * rb_node will have an alignment of 4 or 8 bytes.
+ */
+ uintptr_t rb_info;
+};
+
+#define ARCHIVE_RB_DIR_LEFT 0
+#define ARCHIVE_RB_DIR_RIGHT 1
+
+#define ARCHIVE_RB_TREE_MIN(T) \
+ __archive_rb_tree_iterate((T), NULL, ARCHIVE_RB_DIR_LEFT)
+#define ARCHIVE_RB_TREE_MAX(T) \
+ __archive_rb_tree_iterate((T), NULL, ARCHIVE_RB_DIR_RIGHT)
+#define ARCHIVE_RB_TREE_FOREACH(N, T) \
+ for ((N) = ARCHIVE_RB_TREE_MIN(T); (N); \
+ (N) = __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_RIGHT))
+#define ARCHIVE_RB_TREE_FOREACH_REVERSE(N, T) \
+ for ((N) = ARCHIVE_RB_TREE_MAX(T); (N); \
+ (N) = __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_LEFT))
+
+/*
+ * archive_rbto_compare_nodes_fn:
+ * return a positive value if the first node < the second node.
+ * return a negative value if the first node > the second node.
+ * return 0 if they are considered same.
+ *
+ * archive_rbto_compare_key_fn:
+ * return a positive value if the node < the key.
+ * return a negative value if the node > the key.
+ * return 0 if they are considered same.
+ */
+
+typedef signed int (*const archive_rbto_compare_nodes_fn)(const struct archive_rb_node *,
+ const struct archive_rb_node *);
+typedef signed int (*const archive_rbto_compare_key_fn)(const struct archive_rb_node *,
+ const void *);
+
+struct archive_rb_tree_ops {
+ archive_rbto_compare_nodes_fn rbto_compare_nodes;
+ archive_rbto_compare_key_fn rbto_compare_key;
+};
+
+struct archive_rb_tree {
+ struct archive_rb_node *rbt_root;
+ const struct archive_rb_tree_ops *rbt_ops;
+};
+
+void __archive_rb_tree_init(struct archive_rb_tree *,
+ const struct archive_rb_tree_ops *);
+int __archive_rb_tree_insert_node(struct archive_rb_tree *,
+ struct archive_rb_node *);
+struct archive_rb_node *
+ __archive_rb_tree_find_node(struct archive_rb_tree *, const void *);
+struct archive_rb_node *
+ __archive_rb_tree_find_node_geq(struct archive_rb_tree *, const void *);
+struct archive_rb_node *
+ __archive_rb_tree_find_node_leq(struct archive_rb_tree *, const void *);
+void __archive_rb_tree_remove_node(struct archive_rb_tree *, struct archive_rb_node *);
+struct archive_rb_node *
+ __archive_rb_tree_iterate(struct archive_rb_tree *,
+ struct archive_rb_node *, const unsigned int);
+
+#endif /* ARCHIVE_RB_H_*/
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_data.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_data.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,128 @@
+.\" Copyright (c) 2003-2011 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 22, 2011
+.Dt ARCHIVE_READ_DATA 3
+.Os
+.Sh NAME
+.Nm archive_read_data
+.Nm archive_read_data_block ,
+.Nm archive_read_data_skip ,
+.Nm archive_read_data_into_fd
+.Nd functions for reading streaming archives
+.Sh SYNOPSIS
+.In archive.h
+.Ft ssize_t
+.Fn archive_read_data "struct archive *" "void *buff" "size_t len"
+.Ft int
+.Fo archive_read_data_block
+.Fa "struct archive *"
+.Fa "const void **buff"
+.Fa "size_t *len"
+.Fa "off_t *offset"
+.Fc
+.Ft int
+.Fn archive_read_data_skip "struct archive *"
+.Ft int
+.Fn archive_read_data_into_fd "struct archive *" "int fd"
+.\"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Fn archive_read_data
+Read data associated with the header just read.
+Internally, this is a convenience function that calls
+.Fn archive_read_data_block
+and fills any gaps with nulls so that callers see a single
+continuous stream of data.
+.It Fn archive_read_data_block
+Return the next available block of data for this entry.
+Unlike
+.Fn archive_read_data ,
+the
+.Fn archive_read_data_block
+function avoids copying data and allows you to correctly handle
+sparse files, as supported by some archive formats.
+The library guarantees that offsets will increase and that blocks
+will not overlap.
+Note that the blocks returned from this function can be much larger
+than the block size read from disk, due to compression
+and internal buffer optimizations.
+.It Fn archive_read_data_skip
+A convenience function that repeatedly calls
+.Fn archive_read_data_block
+to skip all of the data for this archive entry.
+Note that this function is invoked automatically by
+.Fn archive_read_next_header2
+if the previous entry was not completely consumed.
+.It Fn archive_read_data_into_fd
+A convenience function that repeatedly calls
+.Fn archive_read_data_block
+to copy the entire entry to the provided file descriptor.
+.El
+.\"
+.Sh RETURN VALUES
+Most functions return zero on success, non-zero on error.
+The possible return codes include:
+.Cm ARCHIVE_OK
+(the operation succeeded),
+.Cm ARCHIVE_WARN
+(the operation succeeded but a non-critical error was encountered),
+.Cm ARCHIVE_EOF
+(end-of-archive was encountered),
+.Cm ARCHIVE_RETRY
+(the operation failed but can be retried),
+and
+.Cm ARCHIVE_FATAL
+(there was a fatal error; the archive should be closed immediately).
+.Pp
+.Fn archive_read_data
+returns a count of bytes actually read or zero at the end of the entry.
+On error, a value of
+.Cm ARCHIVE_FATAL ,
+.Cm ARCHIVE_WARN ,
+or
+.Cm ARCHIVE_RETRY
+is returned.
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read 3 ,
+.Xr archive_read_extract 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_header 3 ,
+.Xr archive_read_open 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_disk.c
--- a/head/contrib/libarchive/libarchive/archive_read_disk.c Fri Mar 02 16:58:39 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +0,0 @@
-/*-
- * Copyright (c) 2003-2009 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer
- * in this position and unchanged.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/contrib/libarchive/libarchive/archive_read_disk.c 228773 2011-12-21 15:18:52Z mm $");
-
-#include "archive.h"
-#include "archive_string.h"
-#include "archive_entry.h"
-#include "archive_private.h"
-#include "archive_read_disk_private.h"
-
-static int _archive_read_free(struct archive *);
-static int _archive_read_close(struct archive *);
-static const char *trivial_lookup_gname(void *, gid_t gid);
-static const char *trivial_lookup_uname(void *, uid_t uid);
-
-static struct archive_vtable *
-archive_read_disk_vtable(void)
-{
- static struct archive_vtable av;
- static int inited = 0;
-
- if (!inited) {
- av.archive_free = _archive_read_free;
- av.archive_close = _archive_read_close;
- }
- return (&av);
-}
-
-const char *
-archive_read_disk_gname(struct archive *_a, gid_t gid)
-{
- struct archive_read_disk *a = (struct archive_read_disk *)_a;
- if (a->lookup_gname != NULL)
- return ((*a->lookup_gname)(a->lookup_gname_data, gid));
- return (NULL);
-}
-
-const char *
-archive_read_disk_uname(struct archive *_a, uid_t uid)
-{
- struct archive_read_disk *a = (struct archive_read_disk *)_a;
- if (a->lookup_uname != NULL)
- return ((*a->lookup_uname)(a->lookup_uname_data, uid));
- return (NULL);
-}
-
-int
-archive_read_disk_set_gname_lookup(struct archive *_a,
- void *private_data,
- const char * (*lookup_gname)(void *private, gid_t gid),
- void (*cleanup_gname)(void *private))
-{
- struct archive_read_disk *a = (struct archive_read_disk *)_a;
- __archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,
- ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup");
-
- if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
- (a->cleanup_gname)(a->lookup_gname_data);
-
- a->lookup_gname = lookup_gname;
- a->cleanup_gname = cleanup_gname;
- a->lookup_gname_data = private_data;
- return (ARCHIVE_OK);
-}
-
-int
-archive_read_disk_set_uname_lookup(struct archive *_a,
- void *private_data,
- const char * (*lookup_uname)(void *private, uid_t uid),
- void (*cleanup_uname)(void *private))
-{
- struct archive_read_disk *a = (struct archive_read_disk *)_a;
- __archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,
- ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup");
-
- if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
- (a->cleanup_uname)(a->lookup_uname_data);
-
- a->lookup_uname = lookup_uname;
- a->cleanup_uname = cleanup_uname;
- a->lookup_uname_data = private_data;
- return (ARCHIVE_OK);
-}
-
-/*
- * Create a new archive_read_disk object and initialize it with global state.
- */
-struct archive *
-archive_read_disk_new(void)
-{
- struct archive_read_disk *a;
-
- a = (struct archive_read_disk *)malloc(sizeof(*a));
- if (a == NULL)
- return (NULL);
- memset(a, 0, sizeof(*a));
- a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
- /* We're ready to write a header immediately. */
- a->archive.state = ARCHIVE_STATE_HEADER;
- a->archive.vtable = archive_read_disk_vtable();
- a->lookup_uname = trivial_lookup_uname;
- a->lookup_gname = trivial_lookup_gname;
- return (&a->archive);
-}
-
-static int
-_archive_read_free(struct archive *_a)
-{
- struct archive_read_disk *a = (struct archive_read_disk *)_a;
-
- if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
- (a->cleanup_gname)(a->lookup_gname_data);
- if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
- (a->cleanup_uname)(a->lookup_uname_data);
- archive_string_free(&a->archive.error_string);
- free(a);
- return (ARCHIVE_OK);
-}
-
-static int
-_archive_read_close(struct archive *_a)
-{
- (void)_a; /* UNUSED */
- return (ARCHIVE_OK);
-}
-
-int
-archive_read_disk_set_symlink_logical(struct archive *_a)
-{
- struct archive_read_disk *a = (struct archive_read_disk *)_a;
- a->symlink_mode = 'L';
- a->follow_symlinks = 1;
- return (ARCHIVE_OK);
-}
-
-int
-archive_read_disk_set_symlink_physical(struct archive *_a)
-{
- struct archive_read_disk *a = (struct archive_read_disk *)_a;
- a->symlink_mode = 'P';
- a->follow_symlinks = 0;
- return (ARCHIVE_OK);
-}
-
-int
-archive_read_disk_set_symlink_hybrid(struct archive *_a)
-{
- struct archive_read_disk *a = (struct archive_read_disk *)_a;
- a->symlink_mode = 'H';
- a->follow_symlinks = 1; /* Follow symlinks initially. */
- return (ARCHIVE_OK);
-}
-
-/*
- * Trivial implementations of gname/uname lookup functions.
- * These are normally overridden by the client, but these stub
- * versions ensure that we always have something that works.
- */
-static const char *
-trivial_lookup_gname(void *private_data, gid_t gid)
-{
- (void)private_data; /* UNUSED */
- (void)gid; /* UNUSED */
- return (NULL);
-}
-
-static const char *
-trivial_lookup_uname(void *private_data, uid_t uid)
-{
- (void)private_data; /* UNUSED */
- (void)uid; /* UNUSED */
- return (NULL);
-}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_disk_posix.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_disk_posix.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,2313 @@
+/*-
+ * Copyright (c) 2003-2009 Tim Kientzle
+ * Copyright (c) 2010,2011 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* This is the tree-walking code for POSIX systems. */
+#if !defined(_WIN32) || defined(__CYGWIN__)
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_LINUX_MAGIC_H
+#include <linux/magic.h>
+#endif
+#ifdef HAVE_DIRECT_H
+#include <direct.h>
+#endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "archive.h"
+#include "archive_string.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+#include "archive_read_disk_private.h"
+
+#ifndef HAVE_FCHDIR
+#error fchdir function required.
+#endif
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/*-
+ * This is a new directory-walking system that addresses a number
+ * of problems I've had with fts(3). In particular, it has no
+ * pathname-length limits (other than the size of 'int'), handles
+ * deep logical traversals, uses considerably less memory, and has
+ * an opaque interface (easier to modify in the future).
+ *
+ * Internally, it keeps a single list of "tree_entry" items that
+ * represent filesystem objects that require further attention.
+ * Non-directories are not kept in memory: they are pulled from
+ * readdir(), returned to the client, then freed as soon as possible.
+ * Any directory entry to be traversed gets pushed onto the stack.
+ *
+ * There is surprisingly little information that needs to be kept for
+ * each item on the stack. Just the name, depth (represented here as the
+ * string length of the parent directory's pathname), and some markers
+ * indicating how to get back to the parent (via chdir("..") for a
+ * regular dir or via fchdir(2) for a symlink).
+ */
+/*
+ * TODO:
+ * 1) Loop checking.
+ * 3) Arbitrary logical traversals by closing/reopening intermediate fds.
+ */
+
+struct restore_time {
+ const char *name;
+ time_t mtime;
+ long mtime_nsec;
+ time_t atime;
+ long atime_nsec;
+ mode_t filetype;
+ int noatime;
+};
+
+struct tree_entry {
+ int depth;
+ struct tree_entry *next;
+ struct tree_entry *parent;
+ struct archive_string name;
+ size_t dirname_length;
+ int64_t dev;
+ int64_t ino;
+ int flags;
+ int filesystem_id;
+ /* How to return back to the parent of a symlink. */
+ int symlink_parent_fd;
+ /* How to restore time of a directory. */
+ struct restore_time restore_time;
+};
+
+struct filesystem {
+ int64_t dev;
+ int synthetic;
+ int remote;
+ int noatime;
+#if defined(HAVE_READDIR_R)
+ size_t name_max;
+#endif
+ long incr_xfer_size;
+ long max_xfer_size;
+ long min_xfer_size;
+ long xfer_align;
+
+ /*
+ * Buffer used for reading file contents.
+ */
+ /* Exactly allocated memory pointer. */
+ unsigned char *allocation_ptr;
+ /* Pointer adjusted to the filesystem alignment . */
+ unsigned char *buff;
+ size_t buff_size;
+};
+
+/* Definitions for tree_entry.flags bitmap. */
+#define isDir 1 /* This entry is a regular directory. */
+#define isDirLink 2 /* This entry is a symbolic link to a directory. */
+#define needsFirstVisit 4 /* This is an initial entry. */
+#define needsDescent 8 /* This entry needs to be previsited. */
+#define needsOpen 16 /* This is a directory that needs to be opened. */
+#define needsAscent 32 /* This entry needs to be postvisited. */
+
+/*
+ * Local data for this package.
+ */
+struct tree {
+ struct tree_entry *stack;
+ struct tree_entry *current;
+ DIR *d;
+#define INVALID_DIR_HANDLE NULL
+ struct dirent *de;
+#if defined(HAVE_READDIR_R)
+ struct dirent *dirent;
+ size_t dirent_allocated;
+#endif
+ int flags;
+ int visit_type;
+ /* Error code from last failed operation. */
+ int tree_errno;
+
+ /* Dynamically-sized buffer for holding path */
+ struct archive_string path;
+
+ /* Last path element */
+ const char *basename;
+ /* Leading dir length */
+ size_t dirname_length;
+
+ int depth;
+ int openCount;
+ int maxOpenCount;
+ int initial_dir_fd;
+ int working_dir_fd;
+
+ struct stat lst;
+ struct stat st;
+ int descend;
+ int nlink;
+ /* How to restore time of a file. */
+ struct restore_time restore_time;
+
+ struct entry_sparse {
+ int64_t length;
+ int64_t offset;
+ } *sparse_list, *current_sparse;
+ int sparse_count;
+ int sparse_list_size;
+
+ char initial_symlink_mode;
+ char symlink_mode;
+ struct filesystem *current_filesystem;
+ struct filesystem *filesystem_table;
+ int current_filesystem_id;
+ int max_filesystem_id;
+ int allocated_filesytem;
+
+ int entry_fd;
+ int entry_eof;
+ int64_t entry_remaining_bytes;
+ int64_t entry_total;
+ unsigned char *entry_buff;
+ size_t entry_buff_size;
+};
+
+/* Definitions for tree.flags bitmap. */
+#define hasStat 16 /* The st entry is valid. */
+#define hasLstat 32 /* The lst entry is valid. */
+#define onWorkingDir 64 /* We are on the working dir where we are
+ * reading directory entry at this time. */
+#define needsRestoreTimes 128
+
+static int
+tree_dir_next_posix(struct tree *t);
+
+#ifdef HAVE_DIRENT_D_NAMLEN
+/* BSD extension; avoids need for a strlen() call. */
+#define D_NAMELEN(dp) (dp)->d_namlen
+#else
+#define D_NAMELEN(dp) (strlen((dp)->d_name))
+#endif
+
+/* Initiate/terminate a tree traversal. */
+static struct tree *tree_open(const char *, int, int);
+static struct tree *tree_reopen(struct tree *, const char *, int);
+static void tree_close(struct tree *);
+static void tree_free(struct tree *);
+static void tree_push(struct tree *, const char *, int, int64_t, int64_t,
+ struct restore_time *);
+static int tree_enter_initial_dir(struct tree *);
+static int tree_enter_working_dir(struct tree *);
+static int tree_current_dir_fd(struct tree *);
+
+/*
+ * tree_next() returns Zero if there is no next entry, non-zero if
+ * there is. Note that directories are visited three times.
+ * Directories are always visited first as part of enumerating their
+ * parent; that is a "regular" visit. If tree_descend() is invoked at
+ * that time, the directory is added to a work list and will
+ * subsequently be visited two more times: once just after descending
+ * into the directory ("postdescent") and again just after ascending
+ * back to the parent ("postascent").
+ *
+ * TREE_ERROR_DIR is returned if the descent failed (because the
+ * directory couldn't be opened, for instance). This is returned
+ * instead of TREE_POSTDESCENT/TREE_POSTASCENT. TREE_ERROR_DIR is not a
+ * fatal error, but it does imply that the relevant subtree won't be
+ * visited. TREE_ERROR_FATAL is returned for an error that left the
+ * traversal completely hosed. Right now, this is only returned for
+ * chdir() failures during ascent.
+ */
+#define TREE_REGULAR 1
+#define TREE_POSTDESCENT 2
+#define TREE_POSTASCENT 3
+#define TREE_ERROR_DIR -1
+#define TREE_ERROR_FATAL -2
+
+static int tree_next(struct tree *);
+
+/*
+ * Return information about the current entry.
+ */
+
+/*
+ * The current full pathname, length of the full pathname, and a name
+ * that can be used to access the file. Because tree does use chdir
+ * extensively, the access path is almost never the same as the full
+ * current path.
+ *
+ * TODO: On platforms that support it, use openat()-style operations
+ * to eliminate the chdir() operations entirely while still supporting
+ * arbitrarily deep traversals. This makes access_path troublesome to
+ * support, of course, which means we'll need a rich enough interface
+ * that clients can function without it. (In particular, we'll need
+ * tree_current_open() that returns an open file descriptor.)
+ *
+ */
+static const char *tree_current_path(struct tree *);
+static const char *tree_current_access_path(struct tree *);
+
+/*
+ * Request the lstat() or stat() data for the current path. Since the
+ * tree package needs to do some of this anyway, and caches the
+ * results, you should take advantage of it here if you need it rather
+ * than make a redundant stat() or lstat() call of your own.
+ */
+static const struct stat *tree_current_stat(struct tree *);
+static const struct stat *tree_current_lstat(struct tree *);
+static int tree_current_is_symblic_link_target(struct tree *);
+
+/* The following functions use tricks to avoid a certain number of
+ * stat()/lstat() calls. */
+/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */
+static int tree_current_is_physical_dir(struct tree *);
+/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */
+static int tree_current_is_dir(struct tree *);
+static int update_current_filesystem(struct archive_read_disk *a,
+ int64_t dev);
+static int setup_current_filesystem(struct archive_read_disk *);
+static int tree_target_is_same_as_parent(struct tree *, const struct stat *);
+
+static int _archive_read_disk_open(struct archive *, const char *);
+static int _archive_read_free(struct archive *);
+static int _archive_read_close(struct archive *);
+static int _archive_read_data_block(struct archive *,
+ const void **, size_t *, int64_t *);
+static int _archive_read_next_header2(struct archive *,
+ struct archive_entry *);
+static const char *trivial_lookup_gname(void *, int64_t gid);
+static const char *trivial_lookup_uname(void *, int64_t uid);
+static int setup_sparse(struct archive_read_disk *, struct archive_entry *);
+static int close_and_restore_time(int fd, struct tree *,
+ struct restore_time *);
+
+
+static struct archive_vtable *
+archive_read_disk_vtable(void)
+{
+ static struct archive_vtable av;
+ static int inited = 0;
+
+ if (!inited) {
+ av.archive_free = _archive_read_free;
+ av.archive_close = _archive_read_close;
+ av.archive_read_data_block = _archive_read_data_block;
+ av.archive_read_next_header2 = _archive_read_next_header2;
+ inited = 1;
+ }
+ return (&av);
+}
+
+const char *
+archive_read_disk_gname(struct archive *_a, int64_t gid)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_disk_gname"))
+ return (NULL);
+ if (a->lookup_gname == NULL)
+ return (NULL);
+ return ((*a->lookup_gname)(a->lookup_gname_data, gid));
+}
+
+const char *
+archive_read_disk_uname(struct archive *_a, int64_t uid)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_disk_uname"))
+ return (NULL);
+ if (a->lookup_uname == NULL)
+ return (NULL);
+ return ((*a->lookup_uname)(a->lookup_uname_data, uid));
+}
+
+int
+archive_read_disk_set_gname_lookup(struct archive *_a,
+ void *private_data,
+ const char * (*lookup_gname)(void *private, int64_t gid),
+ void (*cleanup_gname)(void *private))
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup");
+
+ if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
+ (a->cleanup_gname)(a->lookup_gname_data);
+
+ a->lookup_gname = lookup_gname;
+ a->cleanup_gname = cleanup_gname;
+ a->lookup_gname_data = private_data;
+ return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_set_uname_lookup(struct archive *_a,
+ void *private_data,
+ const char * (*lookup_uname)(void *private, int64_t uid),
+ void (*cleanup_uname)(void *private))
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup");
+
+ if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
+ (a->cleanup_uname)(a->lookup_uname_data);
+
+ a->lookup_uname = lookup_uname;
+ a->cleanup_uname = cleanup_uname;
+ a->lookup_uname_data = private_data;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Create a new archive_read_disk object and initialize it with global state.
+ */
+struct archive *
+archive_read_disk_new(void)
+{
+ struct archive_read_disk *a;
+
+ a = (struct archive_read_disk *)malloc(sizeof(*a));
+ if (a == NULL)
+ return (NULL);
+ memset(a, 0, sizeof(*a));
+ a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
+ a->archive.state = ARCHIVE_STATE_NEW;
+ a->archive.vtable = archive_read_disk_vtable();
+ a->lookup_uname = trivial_lookup_uname;
+ a->lookup_gname = trivial_lookup_gname;
+ a->entry_wd_fd = -1;
+ return (&a->archive);
+}
+
+static int
+_archive_read_free(struct archive *_a)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ int r;
+
+ if (_a == NULL)
+ return (ARCHIVE_OK);
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free");
+
+ if (a->archive.state != ARCHIVE_STATE_CLOSED)
+ r = _archive_read_close(&a->archive);
+ else
+ r = ARCHIVE_OK;
+
+ tree_free(a->tree);
+ if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
+ (a->cleanup_gname)(a->lookup_gname_data);
+ if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
+ (a->cleanup_uname)(a->lookup_uname_data);
+ archive_string_free(&a->archive.error_string);
+ a->archive.magic = 0;
+ __archive_clean(&a->archive);
+ free(a);
+ return (r);
+}
+
+static int
+_archive_read_close(struct archive *_a)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close");
+
+ if (a->archive.state != ARCHIVE_STATE_FATAL)
+ a->archive.state = ARCHIVE_STATE_CLOSED;
+
+ tree_close(a->tree);
+
+ return (ARCHIVE_OK);
+}
+
+static void
+setup_symlink_mode(struct archive_read_disk *a, char symlink_mode,
+ int follow_symlinks)
+{
+ a->symlink_mode = symlink_mode;
+ a->follow_symlinks = follow_symlinks;
+ if (a->tree != NULL) {
+ a->tree->initial_symlink_mode = a->symlink_mode;
+ a->tree->symlink_mode = a->symlink_mode;
+ }
+}
+
+int
+archive_read_disk_set_symlink_logical(struct archive *_a)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_logical");
+ setup_symlink_mode(a, 'L', 1);
+ return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_set_symlink_physical(struct archive *_a)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_physical");
+ setup_symlink_mode(a, 'P', 0);
+ return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_set_symlink_hybrid(struct archive *_a)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_hybrid");
+ setup_symlink_mode(a, 'H', 1);/* Follow symlinks initially. */
+ return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_set_atime_restored(struct archive *_a)
+{
+#ifndef HAVE_UTIMES
+ static int warning_done = 0;
+#endif
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime");
+#ifdef HAVE_UTIMES
+ a->restore_time = 1;
+ if (a->tree != NULL)
+ a->tree->flags |= needsRestoreTimes;
+ return (ARCHIVE_OK);
+#else
+ if (warning_done)
+ /* Warning was already emitted; suppress further warnings. */
+ return (ARCHIVE_OK);
+
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Cannot restore access time on this system");
+ warning_done = 1;
+ return (ARCHIVE_WARN);
+#endif
+}
+
+/*
+ * Trivial implementations of gname/uname lookup functions.
+ * These are normally overridden by the client, but these stub
+ * versions ensure that we always have something that works.
+ */
+static const char *
+trivial_lookup_gname(void *private_data, int64_t gid)
+{
+ (void)private_data; /* UNUSED */
+ (void)gid; /* UNUSED */
+ return (NULL);
+}
+
+static const char *
+trivial_lookup_uname(void *private_data, int64_t uid)
+{
+ (void)private_data; /* UNUSED */
+ (void)uid; /* UNUSED */
+ return (NULL);
+}
+
+/*
+ * Allocate memory for the reading buffer adjusted to the filesystem
+ * alignment.
+ */
+static int
+setup_suitable_read_buffer(struct archive_read_disk *a)
+{
+ struct tree *t = a->tree;
+ struct filesystem *cf = t->current_filesystem;
+ size_t asize;
+ size_t s;
+
+ if (cf->allocation_ptr == NULL) {
+ /* If we couldn't get a filesystem alignment,
+ * we use 4096 as default value but we won't use
+ * O_DIRECT to open() and openat() operations. */
+ long xfer_align = (cf->xfer_align == -1)?4096:cf->xfer_align;
+
+ if (cf->max_xfer_size != -1)
+ asize = cf->max_xfer_size + xfer_align;
+ else {
+ long incr = cf->incr_xfer_size;
+ /* Some platform does not set a proper value to
+ * incr_xfer_size.*/
+ if (incr < 0)
+ incr = cf->min_xfer_size;
+ if (cf->min_xfer_size < 0) {
+ incr = xfer_align;
+ asize = xfer_align;
+ } else
+ asize = cf->min_xfer_size;
+
+ /* Increase a buffer size up to 64K bytes in
+ * a proper incremant size. */
+ while (asize < 1024*64)
+ asize += incr;
+ /* Take a margin to adjust to the filesystem
+ * alignment. */
+ asize += xfer_align;
+ }
+ cf->allocation_ptr = malloc(asize);
+ if (cf->allocation_ptr == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Couldn't allocate memory");
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+ }
+
+ /*
+ * Calculate proper address for the filesystem.
+ */
+ s = (uintptr_t)cf->allocation_ptr;
+ s %= xfer_align;
+ if (s > 0)
+ s = xfer_align - s;
+
+ /*
+ * Set a read buffer pointer in the proper alignment of
+ * the current filesystem.
+ */
+ cf->buff = cf->allocation_ptr + s;
+ cf->buff_size = asize - xfer_align;
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+_archive_read_data_block(struct archive *_a, const void **buff,
+ size_t *size, int64_t *offset)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ struct tree *t = a->tree;
+ int r;
+ ssize_t bytes;
+ size_t buffbytes;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
+ "archive_read_data_block");
+
+ if (t->entry_eof || t->entry_remaining_bytes <= 0) {
+ r = ARCHIVE_EOF;
+ goto abort_read_data;
+ }
+
+ /*
+ * Open the current file.
+ */
+ if (t->entry_fd < 0) {
+ int flags = O_RDONLY | O_BINARY;
+
+ /*
+ * Eliminate or reduce cache effects if we can.
+ *
+ * Carefully consider this to be enabled.
+ */
+#if defined(O_DIRECT) && 0/* Disabled for now */
+ if (t->current_filesystem->xfer_align != -1 &&
+ t->nlink == 1)
+ flags |= O_DIRECT;
+#endif
+#if defined(O_NOATIME)
+ /*
+ * Linux has O_NOATIME flag; use it if we need.
+ */
+ if ((t->flags & needsRestoreTimes) != 0 &&
+ t->restore_time.noatime == 0)
+ flags |= O_NOATIME;
+ do {
+#endif
+#ifdef HAVE_OPENAT
+ t->entry_fd = openat(tree_current_dir_fd(t),
+ tree_current_access_path(t), flags);
+#else
+ tree_enter_working_dir(t);
+ t->entry_fd = open(tree_current_access_path(t), flags);
+#endif
+#if defined(O_NOATIME)
+ /*
+ * When we did open the file with O_NOATIME flag,
+ * if successful, set 1 to t->restore_time.noatime
+ * not to restore an atime of the file later.
+ * if failed by EPERM, retry it without O_NOATIME flag.
+ */
+ if (flags & O_NOATIME) {
+ if (t->entry_fd >= 0)
+ t->restore_time.noatime = 1;
+ else if (errno == EPERM) {
+ flags &= ~O_NOATIME;
+ continue;
+ }
+ }
+ } while (0);
+#endif
+ if (t->entry_fd < 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't open %s", tree_current_path(t));
+ r = ARCHIVE_FAILED;
+ tree_enter_initial_dir(t);
+ goto abort_read_data;
+ }
+ tree_enter_initial_dir(t);
+ }
+
+ /*
+ * Allocate read buffer if not allocated.
+ */
+ if (t->current_filesystem->allocation_ptr == NULL) {
+ r = setup_suitable_read_buffer(a);
+ if (r != ARCHIVE_OK) {
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ goto abort_read_data;
+ }
+ }
+ t->entry_buff = t->current_filesystem->buff;
+ t->entry_buff_size = t->current_filesystem->buff_size;
+
+ buffbytes = t->entry_buff_size;
+ if (buffbytes > (size_t)t->current_sparse->length)
+ buffbytes = (size_t)t->current_sparse->length;
+
+ /*
+ * Skip hole.
+ * TODO: Should we consider t->current_filesystem->xfer_align?
+ */
+ if (t->current_sparse->offset > t->entry_total) {
+ if (lseek(t->entry_fd,
+ (off_t)t->current_sparse->offset, SEEK_SET) < 0) {
+ archive_set_error(&a->archive, errno, "Seek error");
+ r = ARCHIVE_FATAL;
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ goto abort_read_data;
+ }
+ bytes = t->current_sparse->offset - t->entry_total;
+ t->entry_remaining_bytes -= bytes;
+ t->entry_total += bytes;
+ }
+
+ /*
+ * Read file contents.
+ */
+ if (buffbytes > 0) {
+ bytes = read(t->entry_fd, t->entry_buff, buffbytes);
+ if (bytes < 0) {
+ archive_set_error(&a->archive, errno, "Read error");
+ r = ARCHIVE_FATAL;
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ goto abort_read_data;
+ }
+ } else
+ bytes = 0;
+ if (bytes == 0) {
+ /* Get EOF */
+ t->entry_eof = 1;
+ r = ARCHIVE_EOF;
+ goto abort_read_data;
+ }
+ *buff = t->entry_buff;
+ *size = bytes;
+ *offset = t->entry_total;
+ t->entry_total += bytes;
+ t->entry_remaining_bytes -= bytes;
+ if (t->entry_remaining_bytes == 0) {
+ /* Close the current file descriptor */
+ close_and_restore_time(t->entry_fd, t, &t->restore_time);
+ t->entry_fd = -1;
+ t->entry_eof = 1;
+ }
+ t->current_sparse->offset += bytes;
+ t->current_sparse->length -= bytes;
+ if (t->current_sparse->length == 0 && !t->entry_eof)
+ t->current_sparse++;
+ return (ARCHIVE_OK);
+
+abort_read_data:
+ *buff = NULL;
+ *size = 0;
+ *offset = t->entry_total;
+ if (t->entry_fd >= 0) {
+ /* Close the current file descriptor */
+ close_and_restore_time(t->entry_fd, t, &t->restore_time);
+ t->entry_fd = -1;
+ }
+ return (r);
+}
+
+static int
+_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ struct tree *t;
+ const struct stat *st; /* info to use for this entry */
+ const struct stat *lst;/* lstat() information */
+ int descend, fd = -1, r;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+ "archive_read_next_header2");
+
+ t = a->tree;
+ if (t->entry_fd >= 0) {
+ close_and_restore_time(t->entry_fd, t, &t->restore_time);
+ t->entry_fd = -1;
+ }
+#if !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR))
+ /* Restore working directory. */
+ tree_enter_working_dir(t);
+#endif
+ st = NULL;
+ lst = NULL;
+ do {
+ switch (tree_next(t)) {
+ case TREE_ERROR_FATAL:
+ archive_set_error(&a->archive, t->tree_errno,
+ "%s: Unable to continue traversing directory tree",
+ tree_current_path(t));
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ tree_enter_initial_dir(t);
+ return (ARCHIVE_FATAL);
+ case TREE_ERROR_DIR:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "%s: Couldn't visit directory",
+ tree_current_path(t));
+ tree_enter_initial_dir(t);
+ return (ARCHIVE_FAILED);
+ case 0:
+ tree_enter_initial_dir(t);
+ return (ARCHIVE_EOF);
+ case TREE_POSTDESCENT:
+ case TREE_POSTASCENT:
+ break;
+ case TREE_REGULAR:
+ lst = tree_current_lstat(t);
+ if (lst == NULL) {
+ archive_set_error(&a->archive, errno,
+ "%s: Cannot stat",
+ tree_current_path(t));
+ tree_enter_initial_dir(t);
+ return (ARCHIVE_FAILED);
+ }
+ break;
+ }
+ } while (lst == NULL);
+
+ /*
+ * Distinguish 'L'/'P'/'H' symlink following.
+ */
+ switch(t->symlink_mode) {
+ case 'H':
+ /* 'H': After the first item, rest like 'P'. */
+ t->symlink_mode = 'P';
+ /* 'H': First item (from command line) like 'L'. */
+ /* FALLTHROUGH */
+ case 'L':
+ /* 'L': Do descend through a symlink to dir. */
+ descend = tree_current_is_dir(t);
+ /* 'L': Follow symlinks to files. */
+ a->symlink_mode = 'L';
+ a->follow_symlinks = 1;
+ /* 'L': Archive symlinks as targets, if we can. */
+ st = tree_current_stat(t);
+ if (st != NULL && !tree_target_is_same_as_parent(t, st))
+ break;
+ /* If stat fails, we have a broken symlink;
+ * in that case, don't follow the link. */
+ /* FALLTHROUGH */
+ default:
+ /* 'P': Don't descend through a symlink to dir. */
+ descend = tree_current_is_physical_dir(t);
+ /* 'P': Don't follow symlinks to files. */
+ a->symlink_mode = 'P';
+ a->follow_symlinks = 0;
+ /* 'P': Archive symlinks as symlinks. */
+ st = lst;
+ break;
+ }
+
+ if (update_current_filesystem(a, st->st_dev) != ARCHIVE_OK) {
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ tree_enter_initial_dir(t);
+ return (ARCHIVE_FATAL);
+ }
+ t->descend = descend;
+
+ archive_entry_set_pathname(entry, tree_current_path(t));
+ archive_entry_copy_sourcepath(entry, tree_current_access_path(t));
+ archive_entry_copy_stat(entry, st);
+
+ /* Save the times to be restored. */
+ t->restore_time.mtime = archive_entry_mtime(entry);
+ t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry);
+ t->restore_time.atime = archive_entry_atime(entry);
+ t->restore_time.atime_nsec = archive_entry_atime_nsec(entry);
+ t->restore_time.filetype = archive_entry_filetype(entry);
+ t->restore_time.noatime = t->current_filesystem->noatime;
+
+#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+ /*
+ * Open the current file to freely gather its metadata anywhere in
+ * working directory.
+ * Note: A symbolic link file cannot be opened with O_NOFOLLOW.
+ */
+ if (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)
+ fd = openat(tree_current_dir_fd(t), tree_current_access_path(t),
+ O_RDONLY | O_NONBLOCK);
+ /* Restore working directory if openat() operation failed or
+ * the file is a symbolic link. */
+ if (fd < 0)
+ tree_enter_working_dir(t);
+
+ /* The current direcotry fd is needed at
+ * archive_read_disk_entry_from_file() function to read link data
+ * with readlinkat(). */
+ a->entry_wd_fd = tree_current_dir_fd(t);
+#endif
+
+ /*
+ * Populate the archive_entry with metadata from the disk.
+ */
+ r = archive_read_disk_entry_from_file(&(a->archive), entry, fd, st);
+
+ /* Close the file descriptor used for reding the current file
+ * metadata at archive_read_disk_entry_from_file(). */
+ if (fd >= 0)
+ close(fd);
+
+ /* Return to the initial directory. */
+ tree_enter_initial_dir(t);
+ archive_entry_copy_sourcepath(entry, tree_current_path(t));
+
+ /*
+ * EOF and FATAL are persistent at this layer. By
+ * modifying the state, we guarantee that future calls to
+ * read a header or read data will fail.
+ */
+ switch (r) {
+ case ARCHIVE_EOF:
+ a->archive.state = ARCHIVE_STATE_EOF;
+ break;
+ case ARCHIVE_OK:
+ case ARCHIVE_WARN:
+ t->entry_total = 0;
+ if (archive_entry_filetype(entry) == AE_IFREG) {
+ t->nlink = archive_entry_nlink(entry);
+ t->entry_remaining_bytes = archive_entry_size(entry);
+ t->entry_eof = (t->entry_remaining_bytes == 0)? 1: 0;
+ if (!t->entry_eof &&
+ setup_sparse(a, entry) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ } else {
+ t->entry_remaining_bytes = 0;
+ t->entry_eof = 1;
+ }
+ a->archive.state = ARCHIVE_STATE_DATA;
+ break;
+ case ARCHIVE_RETRY:
+ break;
+ case ARCHIVE_FATAL:
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ break;
+ }
+
+ return (r);
+}
+
+static int
+setup_sparse(struct archive_read_disk *a, struct archive_entry *entry)
+{
+ struct tree *t = a->tree;
+ int64_t length, offset;
+ int i;
+
+ t->sparse_count = archive_entry_sparse_reset(entry);
+ if (t->sparse_count+1 > t->sparse_list_size) {
+ free(t->sparse_list);
+ t->sparse_list_size = t->sparse_count + 1;
+ t->sparse_list = malloc(sizeof(t->sparse_list[0]) *
+ t->sparse_list_size);
+ if (t->sparse_list == NULL) {
+ t->sparse_list_size = 0;
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate data");
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+ }
+ }
+ for (i = 0; i < t->sparse_count; i++) {
+ archive_entry_sparse_next(entry, &offset, &length);
+ t->sparse_list[i].offset = offset;
+ t->sparse_list[i].length = length;
+ }
+ if (i == 0) {
+ t->sparse_list[i].offset = 0;
+ t->sparse_list[i].length = archive_entry_size(entry);
+ } else {
+ t->sparse_list[i].offset = archive_entry_size(entry);
+ t->sparse_list[i].length = 0;
+ }
+ t->current_sparse = t->sparse_list;
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Called by the client to mark the directory just returned from
+ * tree_next() as needing to be visited.
+ */
+int
+archive_read_disk_descend(struct archive *_a)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ struct tree *t = a->tree;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
+ "archive_read_disk_descend");
+
+ if (t->visit_type != TREE_REGULAR || !t->descend) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Ignored the request descending the current object");
+ return (ARCHIVE_WARN);
+ }
+
+ if (tree_current_is_physical_dir(t)) {
+ tree_push(t, t->basename, t->current_filesystem_id,
+ t->lst.st_dev, t->lst.st_ino, &t->restore_time);
+ t->stack->flags |= isDir;
+ } else if (tree_current_is_dir(t)) {
+ tree_push(t, t->basename, t->current_filesystem_id,
+ t->st.st_dev, t->st.st_ino, &t->restore_time);
+ t->stack->flags |= isDirLink;
+ }
+ t->descend = 0;
+ return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_open(struct archive *_a, const char *pathname)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED,
+ "archive_read_disk_open");
+ archive_clear_error(&a->archive);
+
+ return (_archive_read_disk_open(_a, pathname));
+}
+
+int
+archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ struct archive_string path;
+ int ret;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED,
+ "archive_read_disk_open_w");
+ archive_clear_error(&a->archive);
+
+ /* Make a char string from a wchar_t string. */
+ archive_string_init(&path);
+ if (archive_string_append_from_wcs(&path, pathname,
+ wcslen(pathname)) != 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Can't convert a path to a char string");
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ ret = ARCHIVE_FATAL;
+ } else
+ ret = _archive_read_disk_open(_a, path.s);
+
+ archive_string_free(&path);
+ return (ret);
+}
+
+static int
+_archive_read_disk_open(struct archive *_a, const char *pathname)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
+ if (a->tree != NULL)
+ a->tree = tree_reopen(a->tree, pathname, a->restore_time);
+ else
+ a->tree = tree_open(pathname, a->symlink_mode,
+ a->restore_time);
+ if (a->tree == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate tar data");
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+ }
+ a->archive.state = ARCHIVE_STATE_HEADER;
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Return a current filesystem ID which is index of the filesystem entry
+ * you've visited through archive_read_disk.
+ */
+int
+archive_read_disk_current_filesystem(struct archive *_a)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
+ "archive_read_disk_current_filesystem");
+
+ return (a->tree->current_filesystem_id);
+}
+
+static int
+update_current_filesystem(struct archive_read_disk *a, int64_t dev)
+{
+ struct tree *t = a->tree;
+ int i, fid;
+
+ if (t->current_filesystem != NULL &&
+ t->current_filesystem->dev == dev)
+ return (ARCHIVE_OK);
+
+ for (i = 0; i < t->max_filesystem_id; i++) {
+ if (t->filesystem_table[i].dev == dev) {
+ /* There is the filesytem ID we've already generated. */
+ t->current_filesystem_id = i;
+ t->current_filesystem = &(t->filesystem_table[i]);
+ return (ARCHIVE_OK);
+ }
+ }
+
+ /*
+ * This is the new filesytem which we have to generate a new ID for.
+ */
+ fid = t->max_filesystem_id++;
+ if (t->max_filesystem_id > t->allocated_filesytem) {
+ size_t s;
+
+ s = t->max_filesystem_id * 2;
+ t->filesystem_table = realloc(t->filesystem_table,
+ s * sizeof(*t->filesystem_table));
+ if (t->filesystem_table == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate tar data");
+ return (ARCHIVE_FATAL);
+ }
+ t->allocated_filesytem = s;
+ }
+ t->current_filesystem_id = fid;
+ t->current_filesystem = &(t->filesystem_table[fid]);
+ t->current_filesystem->dev = dev;
+ t->current_filesystem->allocation_ptr = NULL;
+ t->current_filesystem->buff = NULL;
+
+ /* Setup the current filesystem properties which depend on
+ * platform specific. */
+ return (setup_current_filesystem(a));
+}
+
+/*
+ * Returns 1 if current filesystem is generated filesystem, 0 if it is not
+ * or -1 if it is unknown.
+ */
+int
+archive_read_disk_current_filesystem_is_synthetic(struct archive *_a)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
+ "archive_read_disk_current_filesystem");
+
+ return (a->tree->current_filesystem->synthetic);
+}
+
+/*
+ * Returns 1 if current filesystem is remote filesystem, 0 if it is not
+ * or -1 if it is unknown.
+ */
+int
+archive_read_disk_current_filesystem_is_remote(struct archive *_a)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
+ "archive_read_disk_current_filesystem");
+
+ return (a->tree->current_filesystem->remote);
+}
+
+#if defined(_PC_REC_INCR_XFER_SIZE) && defined(_PC_REC_MAX_XFER_SIZE) &&\
+ defined(_PC_REC_MIN_XFER_SIZE) && defined(_PC_REC_XFER_ALIGN)
+static int
+get_xfer_size(struct tree *t, int fd, const char *path)
+{
+ t->current_filesystem->xfer_align = -1;
+ errno = 0;
+ if (fd >= 0) {
+ t->current_filesystem->incr_xfer_size =
+ fpathconf(fd, _PC_REC_INCR_XFER_SIZE);
+ t->current_filesystem->max_xfer_size =
+ fpathconf(fd, _PC_REC_MAX_XFER_SIZE);
+ t->current_filesystem->min_xfer_size =
+ fpathconf(fd, _PC_REC_MIN_XFER_SIZE);
+ t->current_filesystem->xfer_align =
+ fpathconf(fd, _PC_REC_XFER_ALIGN);
+ } else if (path != NULL) {
+ t->current_filesystem->incr_xfer_size =
+ pathconf(path, _PC_REC_INCR_XFER_SIZE);
+ t->current_filesystem->max_xfer_size =
+ pathconf(path, _PC_REC_MAX_XFER_SIZE);
+ t->current_filesystem->min_xfer_size =
+ pathconf(path, _PC_REC_MIN_XFER_SIZE);
+ t->current_filesystem->xfer_align =
+ pathconf(path, _PC_REC_XFER_ALIGN);
+ }
+ /* At least we need an alignment size. */
+ if (t->current_filesystem->xfer_align == -1)
+ return ((errno == EINVAL)?1:-1);
+ else
+ return (0);
+}
+#else
+static int
+get_xfer_size(struct tree *t, int fd, const char *path)
+{
+ (void)t; /* UNUSED */
+ (void)fd; /* UNUSED */
+ (void)path; /* UNUSED */
+ return (1);/* Not supported */
+}
+#endif
+
+#if defined(HAVE_STATFS) && defined(HAVE_FSTATFS) && defined(MNT_LOCAL) \
+ && !defined(ST_LOCAL)
+
+/*
+ * Gather current filesystem properties on FreeBSD, OpenBSD and Mac OS X.
+ */
+static int
+setup_current_filesystem(struct archive_read_disk *a)
+{
+ struct tree *t = a->tree;
+ struct statfs sfs;
+#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC)
+ struct xvfsconf vfc;
+#endif
+ int r, xr = 0;
+#if !defined(HAVE_STRUCT_STATFS_F_NAMEMAX)
+ long nm;
+#endif
+
+ t->current_filesystem->synthetic = -1;
+ t->current_filesystem->remote = -1;
+ if (tree_current_is_symblic_link_target(t)) {
+#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+ /*
+ * Get file system statistics on any directory
+ * where current is.
+ */
+ int fd = openat(tree_current_dir_fd(t),
+ tree_current_access_path(t), O_RDONLY);
+ if (fd < 0) {
+ archive_set_error(&a->archive, errno,
+ "openat failed");
+ return (ARCHIVE_FAILED);
+ }
+ r = fstatfs(fd, &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, fd, NULL);
+ close(fd);
+#else
+ r = statfs(tree_current_access_path(t), &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, -1, tree_current_access_path(t));
+#endif
+ } else {
+ r = fstatfs(tree_current_dir_fd(t), &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
+ }
+ if (r == -1 || xr == -1) {
+ archive_set_error(&a->archive, errno, "statfs failed");
+ return (ARCHIVE_FAILED);
+ } else if (xr == 1) {
+ /* pathconf(_PC_REX_*) operations are not supported. */
+ t->current_filesystem->xfer_align = sfs.f_bsize;
+ t->current_filesystem->max_xfer_size = -1;
+ t->current_filesystem->min_xfer_size = sfs.f_iosize;
+ t->current_filesystem->incr_xfer_size = sfs.f_iosize;
+ }
+ if (sfs.f_flags & MNT_LOCAL)
+ t->current_filesystem->remote = 0;
+ else
+ t->current_filesystem->remote = 1;
+
+#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC)
+ r = getvfsbyname(sfs.f_fstypename, &vfc);
+ if (r == -1) {
+ archive_set_error(&a->archive, errno, "getvfsbyname failed");
+ return (ARCHIVE_FAILED);
+ }
+ if (vfc.vfc_flags & VFCF_SYNTHETIC)
+ t->current_filesystem->synthetic = 1;
+ else
+ t->current_filesystem->synthetic = 0;
+#endif
+
+#if defined(MNT_NOATIME)
+ if (sfs.f_flags & MNT_NOATIME)
+ t->current_filesystem->noatime = 1;
+ else
+#endif
+ t->current_filesystem->noatime = 0;
+
+#if defined(HAVE_READDIR_R)
+ /* Set maximum filename length. */
+#if defined(HAVE_STRUCT_STATFS_F_NAMEMAX)
+ t->current_filesystem->name_max = sfs.f_namemax;
+#else
+ /* Mac OS X does not have f_namemax in struct statfs. */
+ if (tree_current_is_symblic_link_target(t))
+ nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);
+ else
+ nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
+ if (nm == -1)
+ t->current_filesystem->name_max = NAME_MAX;
+ else
+ t->current_filesystem->name_max = nm;
+#endif
+#endif /* HAVE_READDIR_R */
+ return (ARCHIVE_OK);
+}
+
+#elif (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS)) && defined(ST_LOCAL)
+
+/*
+ * Gather current filesystem properties on NetBSD
+ */
+static int
+setup_current_filesystem(struct archive_read_disk *a)
+{
+ struct tree *t = a->tree;
+ struct statvfs sfs;
+ int r, xr = 0;
+
+ t->current_filesystem->synthetic = -1;
+ if (tree_current_is_symblic_link_target(t)) {
+ r = statvfs(tree_current_access_path(t), &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, -1, tree_current_access_path(t));
+ } else {
+#ifdef HAVE_FSTATVFS
+ r = fstatvfs(tree_current_dir_fd(t), &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
+#else
+ r = statvfs(".", &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, -1, ".");
+#endif
+ }
+ if (r == -1 || xr == -1) {
+ t->current_filesystem->remote = -1;
+ archive_set_error(&a->archive, errno, "statvfs failed");
+ return (ARCHIVE_FAILED);
+ } else if (xr == 1) {
+ /* Usuall come here unless NetBSD supports _PC_REC_XFER_ALIGN
+ * for pathconf() function. */
+ t->current_filesystem->xfer_align = sfs.f_frsize;
+ t->current_filesystem->max_xfer_size = -1;
+ t->current_filesystem->min_xfer_size = sfs.f_iosize;
+ t->current_filesystem->incr_xfer_size = sfs.f_iosize;
+ }
+ if (sfs.f_flag & ST_LOCAL)
+ t->current_filesystem->remote = 0;
+ else
+ t->current_filesystem->remote = 1;
+
+ if (sfs.f_flag & ST_NOATIME)
+ t->current_filesystem->noatime = 1;
+ else
+ t->current_filesystem->noatime = 0;
+
+ /* Set maximum filename length. */
+ t->current_filesystem->name_max = sfs.f_namemax;
+ return (ARCHIVE_OK);
+}
+
+#elif defined(HAVE_SYS_STATFS_H) && defined(HAVE_LINUX_MAGIC_H) &&\
+ defined(HAVE_STATFS) && defined(HAVE_FSTATFS)
+/*
+ * Note: statfs is deprecated since LSB 3.2
+ */
+
+#ifndef CIFS_SUPER_MAGIC
+#define CIFS_SUPER_MAGIC 0xFF534D42
+#endif
+#ifndef DEVFS_SUPER_MAGIC
+#define DEVFS_SUPER_MAGIC 0x1373
+#endif
+
+/*
+ * Gather current filesystem properties on Linux
+ */
+static int
+setup_current_filesystem(struct archive_read_disk *a)
+{
+ struct tree *t = a->tree;
+ struct statfs sfs;
+ struct statvfs svfs;
+ int r, vr = 0, xr = 0;
+
+ if (tree_current_is_symblic_link_target(t)) {
+#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+ /*
+ * Get file system statistics on any directory
+ * where current is.
+ */
+ int fd = openat(tree_current_dir_fd(t),
+ tree_current_access_path(t), O_RDONLY);
+ if (fd < 0) {
+ archive_set_error(&a->archive, errno,
+ "openat failed");
+ return (ARCHIVE_FAILED);
+ }
+ vr = fstatvfs(fd, &svfs);/* for f_flag, mount flags */
+ r = fstatfs(fd, &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, fd, NULL);
+ close(fd);
+#else
+ vr = statvfs(tree_current_access_path(t), &svfs);
+ r = statfs(tree_current_access_path(t), &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, -1, tree_current_access_path(t));
+#endif
+ } else {
+#ifdef HAVE_FSTATFS
+ vr = fstatvfs(tree_current_dir_fd(t), &svfs);
+ r = fstatfs(tree_current_dir_fd(t), &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
+#elif defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+#error "Unexpected case. Please tell us about this error."
+#else
+ vr = statvfs(".", &svfs);
+ r = statfs(".", &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, -1, ".");
+#endif
+ }
+ if (r == -1 || xr == -1 || vr == -1) {
+ t->current_filesystem->synthetic = -1;
+ t->current_filesystem->remote = -1;
+ archive_set_error(&a->archive, errno, "statfs failed");
+ return (ARCHIVE_FAILED);
+ } else if (xr == 1) {
+ /* pathconf(_PC_REX_*) operations are not supported. */
+ t->current_filesystem->xfer_align = svfs.f_frsize;
+ t->current_filesystem->max_xfer_size = -1;
+ t->current_filesystem->min_xfer_size = svfs.f_bsize;
+ t->current_filesystem->incr_xfer_size = svfs.f_bsize;
+ }
+ switch (sfs.f_type) {
+ case AFS_SUPER_MAGIC:
+ case CIFS_SUPER_MAGIC:
+ case CODA_SUPER_MAGIC:
+ case NCP_SUPER_MAGIC:/* NetWare */
+ case NFS_SUPER_MAGIC:
+ case SMB_SUPER_MAGIC:
+ t->current_filesystem->remote = 1;
+ t->current_filesystem->synthetic = 0;
+ break;
+ case DEVFS_SUPER_MAGIC:
+ case PROC_SUPER_MAGIC:
+ case USBDEVICE_SUPER_MAGIC:
+ t->current_filesystem->remote = 0;
+ t->current_filesystem->synthetic = 1;
+ break;
+ default:
+ t->current_filesystem->remote = 0;
+ t->current_filesystem->synthetic = 0;
+ break;
+ }
+
+#if defined(ST_NOATIME)
+ if (svfs.f_flag & ST_NOATIME)
+ t->current_filesystem->noatime = 1;
+ else
+#endif
+ t->current_filesystem->noatime = 0;
+
+#if defined(HAVE_READDIR_R)
+ /* Set maximum filename length. */
+ t->current_filesystem->name_max = sfs.f_namelen;
+#endif
+ return (ARCHIVE_OK);
+}
+
+#elif defined(HAVE_SYS_STATVFS_H) &&\
+ (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS))
+
+/*
+ * Gather current filesystem properties on other posix platform.
+ */
+static int
+setup_current_filesystem(struct archive_read_disk *a)
+{
+ struct tree *t = a->tree;
+ struct statvfs sfs;
+ int r, xr = 0;
+
+ t->current_filesystem->synthetic = -1;/* Not supported */
+ t->current_filesystem->remote = -1;/* Not supported */
+ if (tree_current_is_symblic_link_target(t)) {
+#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+ /*
+ * Get file system statistics on any directory
+ * where current is.
+ */
+ int fd = openat(tree_current_dir_fd(t),
+ tree_current_access_path(t), O_RDONLY);
+ if (fd < 0) {
+ archive_set_error(&a->archive, errno,
+ "openat failed");
+ return (ARCHIVE_FAILED);
+ }
+ r = fstatvfs(fd, &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, fd, NULL);
+ close(fd);
+#else
+ r = statvfs(tree_current_access_path(t), &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, -1, tree_current_access_path(t));
+#endif
+ } else {
+#ifdef HAVE_FSTATVFS
+ r = fstatvfs(tree_current_dir_fd(t), &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
+#elif defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+#error "Unexpected case. Please tell us about this error."
+#else
+ r = statvfs(".", &sfs);
+ if (r == 0)
+ xr = get_xfer_size(t, -1, ".");
+#endif
+ }
+ if (r == -1 || xr == -1) {
+ t->current_filesystem->synthetic = -1;
+ t->current_filesystem->remote = -1;
+ archive_set_error(&a->archive, errno, "statvfs failed");
+ return (ARCHIVE_FAILED);
+ } else if (xr == 1) {
+ /* pathconf(_PC_REX_*) operations are not supported. */
+ t->current_filesystem->xfer_align = sfs.f_frsize;
+ t->current_filesystem->max_xfer_size = -1;
+ t->current_filesystem->min_xfer_size = sfs.f_bsize;
+ t->current_filesystem->incr_xfer_size = sfs.f_bsize;
+ }
+
+#if defined(ST_NOATIME)
+ if (sfs.f_flag & ST_NOATIME)
+ t->current_filesystem->noatime = 1;
+ else
+#endif
+ t->current_filesystem->noatime = 0;
+
+#if defined(HAVE_READDIR_R)
+ /* Set maximum filename length. */
+ t->current_filesystem->name_max = sfs.f_namemax;
+#endif
+ return (ARCHIVE_OK);
+}
+
+#else
+
+/*
+ * Generic: Gather current filesystem properties.
+ * TODO: Is this generic function really needed?
+ */
+static int
+setup_current_filesystem(struct archive_read_disk *a)
+{
+ struct tree *t = a->tree;
+#if defined(_PC_NAME_MAX) && defined(HAVE_READDIR_R)
+ long nm;
+#endif
+ t->current_filesystem->synthetic = -1;/* Not supported */
+ t->current_filesystem->remote = -1;/* Not supported */
+ t->current_filesystem->noatime = 0;
+ (void)get_xfer_size(t, -1, ".");/* Dummy call to avoid build error. */
+ t->current_filesystem->xfer_align = -1;/* Unknown */
+ t->current_filesystem->max_xfer_size = -1;
+ t->current_filesystem->min_xfer_size = -1;
+ t->current_filesystem->incr_xfer_size = -1;
+
+#if defined(HAVE_READDIR_R)
+ /* Set maximum filename length. */
+# if defined(_PC_NAME_MAX)
+ if (tree_current_is_symblic_link_target(t))
+ nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);
+ else
+ nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
+ if (nm == -1)
+# endif /* _PC_NAME_MAX */
+ /*
+ * Some sysmtes (HP-UX or others?) incorrectly defined
+ * NAME_MAX macro to be a smaller value.
+ */
+# if defined(NAME_MAX) && NAME_MAX >= 255
+ t->current_filesystem->name_max = NAME_MAX;
+# else
+ /* No way to get a trusted value of maximum filename
+ * length. */
+ t->current_filesystem->name_max = PATH_MAX;
+# endif /* NAME_MAX */
+# if defined(_PC_NAME_MAX)
+ else
+ t->current_filesystem->name_max = nm;
+# endif /* _PC_NAME_MAX */
+#endif /* HAVE_READDIR_R */
+ return (ARCHIVE_OK);
+}
+
+#endif
+
+static int
+close_and_restore_time(int fd, struct tree *t, struct restore_time *rt)
+{
+#ifndef HAVE_UTIMES
+ (void)a; /* UNUSED */
+ return (close(fd));
+#else
+#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__)
+ struct timespec timespecs[2];
+#endif
+ struct timeval times[2];
+
+ if ((t->flags & needsRestoreTimes) == 0 || rt->noatime) {
+ if (fd >= 0)
+ return (close(fd));
+ else
+ return (0);
+ }
+
+#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__)
+ timespecs[1].tv_sec = rt->mtime;
+ timespecs[1].tv_nsec = rt->mtime_nsec;
+
+ timespecs[0].tv_sec = rt->atime;
+ timespecs[0].tv_nsec = rt->atime_nsec;
+ /* futimens() is defined in POSIX.1-2008. */
+ if (futimens(fd, timespecs) == 0)
+ return (close(fd));
+#endif
+
+ times[1].tv_sec = rt->mtime;
+ times[1].tv_usec = rt->mtime_nsec / 1000;
+
+ times[0].tv_sec = rt->atime;
+ times[0].tv_usec = rt->atime_nsec / 1000;
+
+#if !defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES) && !defined(__CYGWIN__)
+ if (futimes(fd, times) == 0)
+ return (close(fd));
+#endif
+ close(fd);
+#if defined(HAVE_FUTIMESAT)
+ if (futimesat(tree_current_dir_fd(t), rt->name, times) == 0)
+ return (0);
+#endif
+#ifdef HAVE_LUTIMES
+ if (lutimes(rt->name, times) != 0)
+#else
+ if (AE_IFLNK != rt->filetype && utimes(rt->name, times) != 0)
+#endif
+ return (-1);
+#endif
+ return (0);
+}
+
+/*
+ * Add a directory path to the current stack.
+ */
+static void
+tree_push(struct tree *t, const char *path, int filesystem_id,
+ int64_t dev, int64_t ino, struct restore_time *rt)
+{
+ struct tree_entry *te;
+
+ te = malloc(sizeof(*te));
+ memset(te, 0, sizeof(*te));
+ te->next = t->stack;
+ te->parent = t->current;
+ if (te->parent)
+ te->depth = te->parent->depth + 1;
+ t->stack = te;
+ archive_string_init(&te->name);
+ te->symlink_parent_fd = -1;
+ archive_strcpy(&te->name, path);
+ te->flags = needsDescent | needsOpen | needsAscent;
+ te->filesystem_id = filesystem_id;
+ te->dev = dev;
+ te->ino = ino;
+ te->dirname_length = t->dirname_length;
+ te->restore_time.name = te->name.s;
+ if (rt != NULL) {
+ te->restore_time.mtime = rt->mtime;
+ te->restore_time.mtime_nsec = rt->mtime_nsec;
+ te->restore_time.atime = rt->atime;
+ te->restore_time.atime_nsec = rt->atime_nsec;
+ te->restore_time.filetype = rt->filetype;
+ te->restore_time.noatime = rt->noatime;
+ }
+}
+
+/*
+ * Append a name to the current dir path.
+ */
+static void
+tree_append(struct tree *t, const char *name, size_t name_length)
+{
+ size_t size_needed;
+
+ t->path.s[t->dirname_length] = '\0';
+ t->path.length = t->dirname_length;
+ /* Strip trailing '/' from name, unless entire name is "/". */
+ while (name_length > 1 && name[name_length - 1] == '/')
+ name_length--;
+
+ /* Resize pathname buffer as needed. */
+ size_needed = name_length + t->dirname_length + 2;
+ archive_string_ensure(&t->path, size_needed);
+ /* Add a separating '/' if it's needed. */
+ if (t->dirname_length > 0 && t->path.s[archive_strlen(&t->path)-1] != '/')
+ archive_strappend_char(&t->path, '/');
+ t->basename = t->path.s + archive_strlen(&t->path);
+ archive_strncat(&t->path, name, name_length);
+ t->restore_time.name = t->basename;
+}
+
+/*
+ * Open a directory tree for traversal.
+ */
+static struct tree *
+tree_open(const char *path, int symlink_mode, int restore_time)
+{
+ struct tree *t;
+
+ if ((t = malloc(sizeof(*t))) == NULL)
+ return (NULL);
+ memset(t, 0, sizeof(*t));
+ archive_string_init(&t->path);
+ archive_string_ensure(&t->path, 31);
+ t->initial_symlink_mode = symlink_mode;
+ return (tree_reopen(t, path, restore_time));
+}
+
+static struct tree *
+tree_reopen(struct tree *t, const char *path, int restore_time)
+{
+ t->flags = (restore_time)?needsRestoreTimes:0;
+ t->visit_type = 0;
+ t->tree_errno = 0;
+ t->dirname_length = 0;
+ t->depth = 0;
+ t->descend = 0;
+ t->current = NULL;
+ t->d = INVALID_DIR_HANDLE;
+ t->symlink_mode = t->initial_symlink_mode;
+ archive_string_empty(&t->path);
+ t->entry_fd = -1;
+ t->entry_eof = 0;
+ t->entry_remaining_bytes = 0;
+
+ /* First item is set up a lot like a symlink traversal. */
+ tree_push(t, path, 0, 0, 0, NULL);
+ t->stack->flags = needsFirstVisit;
+ t->maxOpenCount = t->openCount = 1;
+ t->initial_dir_fd = open(".", O_RDONLY);
+ t->working_dir_fd = dup(t->initial_dir_fd);
+ return (t);
+}
+
+static int
+tree_descent(struct tree *t)
+{
+ int r = 0;
+
+#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+ int new_fd;
+ t->dirname_length = archive_strlen(&t->path);
+ new_fd = openat(t->working_dir_fd, t->stack->name.s, O_RDONLY);
+ if (new_fd < 0) {
+ t->tree_errno = errno;
+ r = TREE_ERROR_DIR;
+ } else {
+ t->depth++;
+ /* If it is a link, set up fd for the ascent. */
+ if (t->stack->flags & isDirLink) {
+ t->stack->symlink_parent_fd = t->working_dir_fd;
+ t->openCount++;
+ if (t->openCount > t->maxOpenCount)
+ t->maxOpenCount = t->openCount;
+ } else
+ close(t->working_dir_fd);
+ t->working_dir_fd = new_fd;
+ }
+#else
+ /* If it is a link, set up fd for the ascent. */
+ if (t->stack->flags & isDirLink)
+ t->stack->symlink_parent_fd = t->working_dir_fd;
+ else {
+ close(t->working_dir_fd);
+ t->openCount--;
+ }
+ t->working_dir_fd = -1;
+ t->dirname_length = archive_strlen(&t->path);
+ if (chdir(t->stack->name.s) != 0)
+ {
+ t->tree_errno = errno;
+ r = TREE_ERROR_DIR;
+ } else {
+ t->depth++;
+ t->working_dir_fd = open(".", O_RDONLY);
+ t->openCount++;
+ if (t->openCount > t->maxOpenCount)
+ t->maxOpenCount = t->openCount;
+ }
+#endif
+ return (r);
+}
+
+/*
+ * We've finished a directory; ascend back to the parent.
+ */
+static int
+tree_ascend(struct tree *t)
+{
+ struct tree_entry *te;
+ int r = 0, prev_dir_fd;
+
+ te = t->stack;
+ prev_dir_fd = t->working_dir_fd;
+#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+ if (te->flags & isDirLink)
+ t->working_dir_fd = te->symlink_parent_fd;
+ else {
+ int new_fd = openat(t->working_dir_fd, "..", O_RDONLY);
+ if (new_fd < 0) {
+ t->tree_errno = errno;
+ r = TREE_ERROR_FATAL;
+ } else
+ t->working_dir_fd = new_fd;
+ }
+#else
+ if (te->flags & isDirLink) {
+ if (fchdir(te->symlink_parent_fd) != 0) {
+ t->tree_errno = errno;
+ r = TREE_ERROR_FATAL;
+ } else
+ t->working_dir_fd = te->symlink_parent_fd;
+ } else {
+ if (chdir("..") != 0) {
+ t->tree_errno = errno;
+ r = TREE_ERROR_FATAL;
+ } else
+ t->working_dir_fd = open(".", O_RDONLY);
+ }
+#endif
+ if (r == 0) {
+ /* Current directory has been changed, we should
+ * close an fd of previous working directory. */
+ close_and_restore_time(prev_dir_fd, t, &te->restore_time);
+ if (te->flags & isDirLink) {
+ t->openCount--;
+ te->symlink_parent_fd = -1;
+ }
+ t->depth--;
+ }
+ return (r);
+}
+
+/*
+ * Return to the initial directory where tree_open() was performed.
+ */
+static int
+tree_enter_initial_dir(struct tree *t)
+{
+ int r = 0;
+
+ if (t->flags & onWorkingDir) {
+ r = fchdir(t->initial_dir_fd);
+ if (r == 0)
+ t->flags &= ~onWorkingDir;
+ }
+ return (r);
+}
+
+/*
+ * Restore working directory of directory traversals.
+ */
+static int
+tree_enter_working_dir(struct tree *t)
+{
+ int r = 0;
+
+ /*
+ * Change the current directory if really needed.
+ * Sometimes this is unneeded when we did not do
+ * descent.
+ */
+ if (t->depth > 0 && (t->flags & onWorkingDir) == 0) {
+ r = fchdir(t->working_dir_fd);
+ if (r == 0)
+ t->flags |= onWorkingDir;
+ }
+ return (r);
+}
+
+static int
+tree_current_dir_fd(struct tree *t)
+{
+ return (t->working_dir_fd);
+}
+
+/*
+ * Pop the working stack.
+ */
+static void
+tree_pop(struct tree *t)
+{
+ struct tree_entry *te;
+
+ t->path.s[t->dirname_length] = '\0';
+ t->path.length = t->dirname_length;
+ if (t->stack == t->current && t->current != NULL)
+ t->current = t->current->parent;
+ te = t->stack;
+ t->stack = te->next;
+ t->dirname_length = te->dirname_length;
+ t->basename = t->path.s + t->dirname_length;
+ while (t->basename[0] == '/')
+ t->basename++;
+ archive_string_free(&te->name);
+ free(te);
+}
+
+/*
+ * Get the next item in the tree traversal.
+ */
+static int
+tree_next(struct tree *t)
+{
+ int r;
+
+ while (t->stack != NULL) {
+ /* If there's an open dir, get the next entry from there. */
+ if (t->d != INVALID_DIR_HANDLE) {
+ r = tree_dir_next_posix(t);
+ if (r == 0)
+ continue;
+ return (r);
+ }
+
+ if (t->stack->flags & needsFirstVisit) {
+ /* Top stack item needs a regular visit. */
+ t->current = t->stack;
+ tree_append(t, t->stack->name.s,
+ archive_strlen(&(t->stack->name)));
+ /* t->dirname_length = t->path_length; */
+ /* tree_pop(t); */
+ t->stack->flags &= ~needsFirstVisit;
+ return (t->visit_type = TREE_REGULAR);
+ } else if (t->stack->flags & needsDescent) {
+ /* Top stack item is dir to descend into. */
+ t->current = t->stack;
+ tree_append(t, t->stack->name.s,
+ archive_strlen(&(t->stack->name)));
+ t->stack->flags &= ~needsDescent;
+ r = tree_descent(t);
+ if (r != 0) {
+ tree_pop(t);
+ t->visit_type = r;
+ } else
+ t->visit_type = TREE_POSTDESCENT;
+ return (t->visit_type);
+ } else if (t->stack->flags & needsOpen) {
+ t->stack->flags &= ~needsOpen;
+ r = tree_dir_next_posix(t);
+ if (r == 0)
+ continue;
+ return (r);
+ } else if (t->stack->flags & needsAscent) {
+ /* Top stack item is dir and we're done with it. */
+ r = tree_ascend(t);
+ tree_pop(t);
+ t->visit_type = r != 0 ? r : TREE_POSTASCENT;
+ return (t->visit_type);
+ } else {
+ /* Top item on stack is dead. */
+ tree_pop(t);
+ t->flags &= ~hasLstat;
+ t->flags &= ~hasStat;
+ }
+ }
+ return (t->visit_type = 0);
+}
+
+static int
+tree_dir_next_posix(struct tree *t)
+{
+ int r;
+ const char *name;
+ size_t namelen;
+
+ if (t->d == NULL) {
+#if defined(HAVE_READDIR_R)
+ size_t dirent_size;
+#endif
+
+#if defined(HAVE_FDOPENDIR)
+ if ((t->d = fdopendir(dup(t->working_dir_fd))) == NULL) {
+#else
+ if ((t->d = opendir(".")) == NULL) {
+#endif
+ r = tree_ascend(t); /* Undo "chdir" */
+ tree_pop(t);
+ t->tree_errno = errno;
+ t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
+ return (t->visit_type);
+ }
+#if defined(HAVE_READDIR_R)
+ dirent_size = offsetof(struct dirent, d_name) +
+ t->filesystem_table[t->current->filesystem_id].name_max + 1;
+ if (t->dirent == NULL || t->dirent_allocated < dirent_size) {
+ free(t->dirent);
+ t->dirent = malloc(dirent_size);
+ if (t->dirent == NULL) {
+ closedir(t->d);
+ t->d = INVALID_DIR_HANDLE;
+ (void)tree_ascend(t);
+ tree_pop(t);
+ t->tree_errno = ENOMEM;
+ t->visit_type = TREE_ERROR_DIR;
+ return (t->visit_type);
+ }
+ t->dirent_allocated = dirent_size;
+ }
+#endif /* HAVE_READDIR_R */
+ }
+ for (;;) {
+#if defined(HAVE_READDIR_R)
+ r = readdir_r(t->d, t->dirent, &t->de);
+ if (r != 0 || t->de == NULL) {
+#else
+ errno = 0;
+ t->de = readdir(t->d);
+ if (t->de == NULL) {
+ r = errno;
+#endif
+ closedir(t->d);
+ t->d = INVALID_DIR_HANDLE;
+ if (r != 0) {
+ t->tree_errno = r;
+ t->visit_type = TREE_ERROR_DIR;
+ return (t->visit_type);
+ } else
+ return (0);
+ }
+ name = t->de->d_name;
+ namelen = D_NAMELEN(t->de);
+ t->flags &= ~hasLstat;
+ t->flags &= ~hasStat;
+ if (name[0] == '.' && name[1] == '\0')
+ continue;
+ if (name[0] == '.' && name[1] == '.' && name[2] == '\0')
+ continue;
+ tree_append(t, name, namelen);
+ return (t->visit_type = TREE_REGULAR);
+ }
+}
+
+
+/*
+ * Get the stat() data for the entry just returned from tree_next().
+ */
+static const struct stat *
+tree_current_stat(struct tree *t)
+{
+ if (!(t->flags & hasStat)) {
+#ifdef HAVE_FSTATAT
+ if (fstatat(tree_current_dir_fd(t),
+ tree_current_access_path(t), &t->st, 0) != 0)
+#else
+ if (stat(tree_current_access_path(t), &t->st) != 0)
+#endif
+ return NULL;
+ t->flags |= hasStat;
+ }
+ return (&t->st);
+}
+
+/*
+ * Get the lstat() data for the entry just returned from tree_next().
+ */
+static const struct stat *
+tree_current_lstat(struct tree *t)
+{
+ if (!(t->flags & hasLstat)) {
+#ifdef HAVE_FSTATAT
+ if (fstatat(tree_current_dir_fd(t),
+ tree_current_access_path(t), &t->lst,
+ AT_SYMLINK_NOFOLLOW) != 0)
+#else
+ if (lstat(tree_current_access_path(t), &t->lst) != 0)
+#endif
+ return NULL;
+ t->flags |= hasLstat;
+ }
+ return (&t->lst);
+}
+
+/*
+ * Test whether current entry is a dir or link to a dir.
+ */
+static int
+tree_current_is_dir(struct tree *t)
+{
+ const struct stat *st;
+ /*
+ * If we already have lstat() info, then try some
+ * cheap tests to determine if this is a dir.
+ */
+ if (t->flags & hasLstat) {
+ /* If lstat() says it's a dir, it must be a dir. */
+ if (S_ISDIR(tree_current_lstat(t)->st_mode))
+ return 1;
+ /* Not a dir; might be a link to a dir. */
+ /* If it's not a link, then it's not a link to a dir. */
+ if (!S_ISLNK(tree_current_lstat(t)->st_mode))
+ return 0;
+ /*
+ * It's a link, but we don't know what it's a link to,
+ * so we'll have to use stat().
+ */
+ }
+
+ st = tree_current_stat(t);
+ /* If we can't stat it, it's not a dir. */
+ if (st == NULL)
+ return 0;
+ /* Use the definitive test. Hopefully this is cached. */
+ return (S_ISDIR(st->st_mode));
+}
+
+/*
+ * Test whether current entry is a physical directory. Usually, we
+ * already have at least one of stat() or lstat() in memory, so we
+ * use tricks to try to avoid an extra trip to the disk.
+ */
+static int
+tree_current_is_physical_dir(struct tree *t)
+{
+ const struct stat *st;
+
+ /*
+ * If stat() says it isn't a dir, then it's not a dir.
+ * If stat() data is cached, this check is free, so do it first.
+ */
+ if ((t->flags & hasStat)
+ && (!S_ISDIR(tree_current_stat(t)->st_mode)))
+ return 0;
+
+ /*
+ * Either stat() said it was a dir (in which case, we have
+ * to determine whether it's really a link to a dir) or
+ * stat() info wasn't available. So we use lstat(), which
+ * hopefully is already cached.
+ */
+
+ st = tree_current_lstat(t);
+ /* If we can't stat it, it's not a dir. */
+ if (st == NULL)
+ return 0;
+ /* Use the definitive test. Hopefully this is cached. */
+ return (S_ISDIR(st->st_mode));
+}
+
+/*
+ * Test whether the same file has been in the tree as its parent.
+ */
+static int
+tree_target_is_same_as_parent(struct tree *t, const struct stat *st)
+{
+ struct tree_entry *te;
+
+ for (te = t->current->parent; te != NULL; te = te->parent) {
+ if (te->dev == (int64_t)st->st_dev &&
+ te->ino == (int64_t)st->st_ino)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Test whether the current file is symbolic link target and
+ * on the other filesystem.
+ */
+static int
+tree_current_is_symblic_link_target(struct tree *t)
+{
+ static const struct stat *lst, *st;
+
+ lst = tree_current_lstat(t);
+ st = tree_current_stat(t);
+ return (st != NULL &&
+ (int64_t)st->st_dev == t->current_filesystem->dev &&
+ st->st_dev != lst->st_dev);
+}
+
+/*
+ * Return the access path for the entry just returned from tree_next().
+ */
+static const char *
+tree_current_access_path(struct tree *t)
+{
+ return (t->basename);
+}
+
+/*
+ * Return the full path for the entry just returned from tree_next().
+ */
+static const char *
+tree_current_path(struct tree *t)
+{
+ return (t->path.s);
+}
+
+/*
+ * Terminate the traversal.
+ */
+static void
+tree_close(struct tree *t)
+{
+
+ if (t == NULL)
+ return;
+ if (t->entry_fd >= 0) {
+ close_and_restore_time(t->entry_fd, t, &t->restore_time);
+ t->entry_fd = -1;
+ }
+ /* Close the handle of readdir(). */
+ if (t->d != INVALID_DIR_HANDLE) {
+ closedir(t->d);
+ t->d = INVALID_DIR_HANDLE;
+ }
+ /* Release anything remaining in the stack. */
+ while (t->stack != NULL) {
+ if (t->stack->flags & isDirLink)
+ close(t->stack->symlink_parent_fd);
+ tree_pop(t);
+ }
+ if (t->working_dir_fd >= 0) {
+ close(t->working_dir_fd);
+ t->working_dir_fd = -1;
+ }
+ if (t->initial_dir_fd >= 0) {
+ close(t->initial_dir_fd);
+ t->initial_dir_fd = -1;
+ }
+}
+
+/*
+ * Release any resources.
+ */
+static void
+tree_free(struct tree *t)
+{
+ int i;
+
+ if (t == NULL)
+ return;
+ archive_string_free(&t->path);
+#if defined(HAVE_READDIR_R)
+ free(t->dirent);
+#endif
+ free(t->sparse_list);
+ for (i = 0; i < t->max_filesystem_id; i++)
+ free(t->filesystem_table[i].allocation_ptr);
+ free(t->filesystem_table);
+ free(t);
+}
+
+#endif
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_extract.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_extract.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,135 @@
+.\" Copyright (c) 2003-2011 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 22, 2011
+.Dt ARCHIVE_READ_EXTRACT 3
+.Os
+.Sh NAME
+.Nm archive_read_extract ,
+.Nm archive_read_extract2 ,
+.Nm archive_read_extract_set_progress_callback
+.Nd functions for reading streaming archives
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fo archive_read_extract
+.Fa "struct archive *"
+.Fa "struct archive_entry *"
+.Fa "int flags"
+.Fc
+.Ft int
+.Fo archive_read_extract2
+.Fa "struct archive *src"
+.Fa "struct archive_entry *"
+.Fa "struct archive *dest"
+.Fc
+.Ft void
+.Fo archive_read_extract_set_progress_callback
+.Fa "struct archive *"
+.Fa "void (*func)(void *)"
+.Fa "void *user_data"
+.Fc
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Fn archive_read_extract , Fn archive_read_extract_set_skip_file
+A convenience function that wraps the corresponding
+.Xr archive_write_disk 3
+interfaces.
+The first call to
+.Fn archive_read_extract
+creates a restore object using
+.Xr archive_write_disk_new 3
+and
+.Xr archive_write_disk_set_standard_lookup 3 ,
+then transparently invokes
+.Xr archive_write_disk_set_options 3 ,
+.Xr archive_write_header 3 ,
+.Xr archive_write_data 3 ,
+and
+.Xr archive_write_finish_entry 3
+to create the entry on disk and copy data into it.
+The
+.Va flags
+argument is passed unmodified to
+.Xr archive_write_disk_set_options 3 .
+.It Fn archive_read_extract2
+This is another version of
+.Fn archive_read_extract
+that allows you to provide your own restore object.
+In particular, this allows you to override the standard lookup functions
+using
+.Xr archive_write_disk_set_group_lookup 3 ,
+and
+.Xr archive_write_disk_set_user_lookup 3 .
+Note that
+.Fn archive_read_extract2
+does not accept a
+.Va flags
+argument; you should use
+.Fn archive_write_disk_set_options
+to set the restore options yourself.
+.It Fn archive_read_extract_set_progress_callback
+Sets a pointer to a user-defined callback that can be used
+for updating progress displays during extraction.
+The progress function will be invoked during the extraction of large
+regular files.
+The progress function will be invoked with the pointer provided to this call.
+Generally, the data pointed to should include a reference to the archive
+object and the archive_entry object so that various statistics
+can be retrieved for the progress display.
+.El
+.\"
+.Sh RETURN VALUES
+Most functions return zero on success, non-zero on error.
+The possible return codes include:
+.Cm ARCHIVE_OK
+(the operation succeeded),
+.Cm ARCHIVE_WARN
+(the operation succeeded but a non-critical error was encountered),
+.Cm ARCHIVE_EOF
+(end-of-archive was encountered),
+.Cm ARCHIVE_RETRY
+(the operation failed but can be retried),
+and
+.Cm ARCHIVE_FATAL
+(there was a fatal error; the archive should be closed immediately).
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_open 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_filter.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_filter.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,127 @@
+.\" Copyright (c) 2003-2011 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 19, 2011
+.Dt ARCHIVE_READ_FILTER 3
+.Os
+.Sh NAME
+.Nm archive_read_support_filter_all ,
+.Nm archive_read_support_filter_bzip2 ,
+.Nm archive_read_support_filter_compress ,
+.Nm archive_read_support_filter_gzip ,
+.Nm archive_read_support_filter_lzma ,
+.Nm archive_read_support_filter_none ,
+.Nm archive_read_support_filter_xz ,
+.Nm archive_read_support_filter_program ,
+.Nm archive_read_support_filter_program_signature
+.Nd functions for reading streaming archives
+.\"
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fn archive_read_support_filter_all "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_bzip2 "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_compress "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_gzip "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_lzma "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_none "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_xz "struct archive *"
+.Ft int
+.Fo archive_read_support_filter_program
+.Fa "struct archive *"
+.Fa "const char *cmd"
+.Fc
+.Ft int
+.Fo archive_read_support_filter_program_signature
+.Fa "struct archive *"
+.Fa "const char *cmd"
+.Fa "const void *signature"
+.Fa "size_t signature_length"
+.Fc
+.\"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Xo
+.Fn archive_read_support_filter_bzip2 ,
+.Fn archive_read_support_filter_compress ,
+.Fn archive_read_support_filter_gzip ,
+.Fn archive_read_support_filter_lzma ,
+.Fn archive_read_support_filter_none ,
+.Fn archive_read_support_filter_xz
+.Xc
+Enables auto-detection code and decompression support for the
+specified compression.
+These functions may fall back on external programs if an appropriate
+library was not available at build time.
+Decompression using an external program is usually slower than
+decompression through built-in libraries.
+Note that
+.Dq none
+is always enabled by default.
+.It Fn archive_read_support_filter_all
+Enables all available decompression filters.
+.It Fn archive_read_support_filter_program
+Data is fed through the specified external program before being dearchived.
+Note that this disables automatic detection of the compression format,
+so it makes no sense to specify this in conjunction with any other
+decompression option.
+.It Fn archive_read_support_filter_program_signature
+This feeds data through the specified external program
+but only if the initial bytes of the data match the specified
+signature value.
+.El
+.\"
+.\". Sh EXAMPLE
+.\"
+.Sh RETURN VALUES
+These functions return
+.Cm ARCHIVE_OK
+if the compression is fully supported,
+.Cm ARCHIVE_WARN
+if the compression is supported only through an external program.
+.Pp
+.Fn archive_read_support_filter_none
+always succeeds.
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr libarchive 3 ,
+.Xr archive_read 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_format 3
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_format.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_format.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,175 @@
+.\" Copyright (c) 2003-2011 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
+.\"
+.Dd March 19, 2011
+.Dt ARCHIVE_READ_FORMAT 3
+.Os
+.Sh NAME
+.Nm archive_read_support_format_7zip ,
+.Nm archive_read_support_format_all ,
+.Nm archive_read_support_format_ar ,
+.Nm archive_read_support_format_by_code ,
+.Nm archive_read_support_format_cab ,
+.Nm archive_read_support_format_cpio ,
+.Nm archive_read_support_format_empty ,
+.Nm archive_read_support_format_iso9660 ,
+.Nm archive_read_support_format_lha ,
+.Nm archive_read_support_format_mtree,
+.Nm archive_read_support_format_rar,
+.Nm archive_read_support_format_raw,
+.Nm archive_read_support_format_tar ,
+.Nm archive_read_support_format_xar ,
+.Nm archive_read_support_format_zip
+.Nd functions for reading streaming archives
+.\"
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fn archive_read_support_format_7zip "struct archive *"
+.Ft int
+.Fn archive_read_support_format_all "struct archive *"
+.Ft int
+.Fn archive_read_support_format_ar "struct archive *"
+.Ft int
+.Fn archive_read_support_format_by_code "struct archive *" "int"
+.Ft int
+.Fn archive_read_support_format_cab "struct archive *"
+.Ft int
+.Fn archive_read_support_format_cpio "struct archive *"
+.Ft int
+.Fn archive_read_support_format_empty "struct archive *"
+.Ft int
+.Fn archive_read_support_format_iso9660 "struct archive *"
+.Ft int
+.Fn archive_read_support_format_lha "struct archive *"
+.Ft int
+.Fn archive_read_support_format_mtree "struct archive *"
+.Ft int
+.Fn archive_read_support_format_rar "struct archive *"
+.Ft int
+.Fn archive_read_support_format_raw "struct archive *"
+.Ft int
+.Fn archive_read_support_format_tar "struct archive *"
+.Ft int
+.Fn archive_read_support_format_xar "struct archive *"
+.Ft int
+.Fn archive_read_support_format_zip "struct archive *"
+.\"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Xo
+.Fn archive_read_support_format_7zip ,
+.Fn archive_read_support_format_ar ,
+.Fn archive_read_support_format_cab ,
+.Fn archive_read_support_format_cpio ,
+.Fn archive_read_support_format_iso9660 ,
+.Fn archive_read_support_format_lha ,
+.Fn archive_read_support_format_mtree ,
+.Fn archive_read_support_format_rar ,
+.Fn archive_read_support_format_raw ,
+.Fn archive_read_support_format_tar ,
+.Fn archive_read_support_format_xar ,
+.Fn archive_read_support_format_zip
+.Xc
+Enables support---including auto-detection code---for the
+specified archive format.
+For example,
+.Fn archive_read_support_format_tar
+enables support for a variety of standard tar formats, old-style tar,
+ustar, pax interchange format, and many common variants.
+.It Fn archive_read_support_format_all
+Enables support for all available formats except the
+.Dq raw
+format (see below).
+.It Fn archive_read_support_format_by_code
+Enables a single format specified by the format code.
+This can be useful when reading a single archive twice;
+use
+.Fn archive_format
+after reading the first time and pass the resulting code
+to this function to selectively enable only the necessary
+format support.
+Note: In statically-linked executables, this will cause
+your program to include support for every format.
+If executable size is a concern, you may wish to avoid
+using this function.
+.It Fn archive_read_support_format_empty
+Enables support for treating empty files as empty archives.
+Because empty files are valid for several different formats,
+it is not possible to accurately determine a format for
+an empty file based purely on contents.
+So empty files are treated by libarchive as a distinct
+format.
+.It Fn archive_read_support_format_raw
+The
+.Dq raw
+format handler allows libarchive to be used to read arbitrary data.
+It treats any data stream as an archive with a single entry.
+The pathname of this entry is
+.Dq data ;
+all other entry fields are unset.
+This is not enabled by
+.Fn archive_read_support_format_all
+in order to avoid erroneous handling of damaged archives.
+.El
+.\" .Sh EXAMPLE
+.Sh RETURN VALUES
+These functions return
+.Cm ARCHIVE_OK
+on success, or
+.Cm ARCHIVE_FATAL .
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
+.Sh BUGS
+Many traditional archiver programs treat
+empty files as valid empty archives.
+For example, many implementations of
+.Xr tar 1
+allow you to append entries to an empty file.
+Of course, it is impossible to determine the format of an empty file
+by inspecting the contents, so this library treats empty files as
+having a special
+.Dq empty
+format.
+.Pp
+Using the
+.Dq raw
+handler together with any other handler will often work
+but can produce surprising results.
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_free.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_free.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,91 @@
+.\" Copyright (c) 2003-2011 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
+.\"
+.Dd March 20, 2011
+.Dt ARCHIVE_READ_FREE 3
+.Os
+.Sh NAME
+.Nm archive_read_close ,
+.Nm archive_read_finish ,
+.Nm archive_read_free
+.Nd functions for reading streaming archives
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fn archive_read_close "struct archive *"
+.Ft int
+.Fn archive_read_finish "struct archive *"
+.Ft int
+.Fn archive_read_free "struct archive *"
+.\"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Fn archive_read_close
+Complete the archive and invoke the close callback.
+.It Fn archive_read_finish
+This is a deprecated synonym for
+.Fn archive_read_free .
+The new name was introduced with libarchive 3.0.
+Applications that need to compile with either libarchive 2
+or libarchive 3 should continue to use the
+.Fn archive_read_finish
+name.
+Both names will be supported until libarchive 4.0 is
+released, which is not expected to occur earlier
+than 2013.
+.It Fn archive_read_free
+Invokes
+.Fn archive_read_close
+if it was not invoked manually, then release all resources.
+Note: In libarchive 1.x, this function was declared to return
+.Ft void ,
+which made it impossible to detect certain errors when
+.Fn archive_read_close
+was invoked implicitly from this function.
+The declaration is corrected beginning with libarchive 2.0.
+.El
+.Sh RETURN VALUES
+These functions return
+.Cm ARCHIVE_OK
+on success, or
+.Cm ARCHIVE_FATAL .
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr libarchive 3 ,
+.Xr archive_read_new 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_open 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_header.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_header.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,89 @@
+.\" Copyright (c) 2003-2011 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 22, 2011
+.Dt ARCHIVE_READ_HEADER 3
+.Os
+.Sh NAME
+.Nm archive_read_next_header ,
+.Nm archive_read_next_header2
+.Nd functions for reading streaming archives
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fn archive_read_next_header "struct archive *" "struct archive_entry **"
+.Ft int
+.Fn archive_read_next_header2 "struct archive *" "struct archive_entry *"
+.\"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Fn archive_read_next_header
+Read the header for the next entry and return a pointer to
+a
+.Tn struct archive_entry .
+This is a convenience wrapper around
+.Fn archive_read_next_header2
+that reuses an internal
+.Tn struct archive_entry
+object for each request.
+.It Fn archive_read_next_header2
+Read the header for the next entry and populate the provided
+.Tn struct archive_entry .
+.El
+.\"
+.Sh RETURN VALUES
+These functions return
+.Cm ARCHIVE_OK
+(the operation succeeded),
+.Cm ARCHIVE_WARN
+(the operation succeeded but a non-critical error was encountered),
+.Cm ARCHIVE_EOF
+(end-of-archive was encountered),
+.Cm ARCHIVE_RETRY
+(the operation failed but can be retried),
+and
+.Cm ARCHIVE_FATAL
+(there was a fatal error; the archive should be closed immediately).
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_extract 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_open 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_new.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_new.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,57 @@
+.\" Copyright (c) 2003-2011 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
+.\"
+.Dd March 20, 2011
+.Dt ARCHIVE_READ_NEW 3
+.Os
+.Sh NAME
+.Nm archive_read_new
+.Nd functions for reading streaming archives
+.Sh SYNOPSIS
+.In archive.h
+.Ft struct archive *
+.Fn archive_read_new "void"
+.Sh DESCRIPTION
+Allocates and initializes a
+.Tn struct archive
+object suitable for reading from an archive.
+.Dv NULL
+is returned on error.
+.Pp
+A complete description of the
+.Tn struct archive
+object can be found in the overview manual page for
+.Xr libarchive 3 .
+.\" .Sh ERRORS
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_open.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_open.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,231 @@
+.\" Copyright (c) 2003-2011 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
+.\"
+.Dd March 19, 2011
+.Dt ARCHIVE_READ_OPEN 3
+.Os
+.Sh NAME
+.Nm archive_read_open ,
+.Nm archive_read_open2 ,
+.Nm archive_read_open_fd ,
+.Nm archive_read_open_FILE ,
+.Nm archive_read_open_filename ,
+.Nm archive_read_open_memory ,
+.Nd functions for reading streaming archives
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fo archive_read_open
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "archive_open_callback *"
+.Fa "archive_read_callback *"
+.Fa "archive_close_callback *"
+.Fc
+.Ft int
+.Fo archive_read_open2
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "archive_open_callback *"
+.Fa "archive_read_callback *"
+.Fa "archive_skip_callback *"
+.Fa "archive_close_callback *"
+.Fc
+.Ft int
+.Fn archive_read_open_FILE "struct archive *" "FILE *file"
+.Ft int
+.Fn archive_read_open_fd "struct archive *" "int fd" "size_t block_size"
+.Ft int
+.Fo archive_read_open_filename
+.Fa "struct archive *"
+.Fa "const char *filename"
+.Fa "size_t block_size"
+.Fc
+.Ft int
+.Fn archive_read_open_memory "struct archive *" "void *buff" "size_t size"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Fn archive_read_open
+The same as
+.Fn archive_read_open2 ,
+except that the skip callback is assumed to be
+.Dv NULL .
+.It Fn archive_read_open2
+Freeze the settings, open the archive, and prepare for reading entries.
+This is the most generic version of this call, which accepts
+four callback functions.
+Most clients will want to use
+.Fn archive_read_open_filename ,
+.Fn archive_read_open_FILE ,
+.Fn archive_read_open_fd ,
+or
+.Fn archive_read_open_memory
+instead.
+The library invokes the client-provided functions to obtain
+raw bytes from the archive.
+.It Fn archive_read_open_FILE
+Like
+.Fn archive_read_open ,
+except that it accepts a
+.Ft "FILE *"
+pointer.
+This function should not be used with tape drives or other devices
+that require strict I/O blocking.
+.It Fn archive_read_open_fd
+Like
+.Fn archive_read_open ,
+except that it accepts a file descriptor and block size rather than
+a set of function pointers.
+Note that the file descriptor will not be automatically closed at
+end-of-archive.
+This function is safe for use with tape drives or other blocked devices.
+.It Fn archive_read_open_file
+This is a deprecated synonym for
+.Fn archive_read_open_filename .
+.It Fn archive_read_open_filename
+Like
+.Fn archive_read_open ,
+except that it accepts a simple filename and a block size.
+A NULL filename represents standard input.
+This function is safe for use with tape drives or other blocked devices.
+.It Fn archive_read_open_memory
+Like
+.Fn archive_read_open ,
+except that it accepts a pointer and size of a block of
+memory containing the archive data.
+.El
+.Pp
+A complete description of the
+.Tn struct archive
+and
+.Tn struct archive_entry
+objects can be found in the overview manual page for
+.Xr libarchive 3 .
+.Sh CLIENT CALLBACKS
+The callback functions must match the following prototypes:
+.Bl -item -offset indent
+.It
+.Ft typedef ssize_t
+.Fo archive_read_callback
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "const void **buffer"
+.Fc
+.It
+.Ft typedef off_t
+.Fo archive_skip_callback
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "off_t request"
+.Fc
+.It
+.Ft typedef int
+.Fn archive_open_callback "struct archive *" "void *client_data"
+.It
+.Ft typedef int
+.Fn archive_close_callback "struct archive *" "void *client_data"
+.El
+.Pp
+The open callback is invoked by
+.Fn archive_open .
+It should return
+.Cm ARCHIVE_OK
+if the underlying file or data source is successfully
+opened.
+If the open fails, it should call
+.Fn archive_set_error
+to register an error code and message and return
+.Cm ARCHIVE_FATAL .
+.Pp
+The read callback is invoked whenever the library
+requires raw bytes from the archive.
+The read callback should read data into a buffer,
+set the
+.Li const void **buffer
+argument to point to the available data, and
+return a count of the number of bytes available.
+The library will invoke the read callback again
+only after it has consumed this data.
+The library imposes no constraints on the size
+of the data blocks returned.
+On end-of-file, the read callback should
+return zero.
+On error, the read callback should invoke
+.Fn archive_set_error
+to register an error code and message and
+return -1.
+.Pp
+The skip callback is invoked when the
+library wants to ignore a block of data.
+The return value is the number of bytes actually
+skipped, which may differ from the request.
+If the callback cannot skip data, it should return
+zero.
+If the skip callback is not provided (the
+function pointer is
+.Dv NULL ),
+the library will invoke the read function
+instead and simply discard the result.
+A skip callback can provide significant
+performance gains when reading uncompressed
+archives from slow disk drives or other media
+that can skip quickly.
+.Pp
+The close callback is invoked by archive_close when
+the archive processing is complete.
+The callback should return
+.Cm ARCHIVE_OK
+on success.
+On failure, the callback should invoke
+.Fn archive_set_error
+to register an error code and message and
+return
+.Cm ARCHIVE_FATAL.
+.\" .Sh EXAMPLE
+.\"
+.Sh RETURN VALUES
+These functions return
+.Cm ARCHIVE_OK
+on success, or
+.Cm ARCHIVE_FATAL .
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_set_options.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_set_options.3 Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,207 @@
+.\" Copyright (c) 2011 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 13, 2009
+.Dt ARCHIVE_READ_OPTIONS 3
+.Os
+.Sh NAME
+.Nm archive_read_set_filter_option ,
+.Nm archive_read_set_format_option ,
+.Nm archive_read_set_option ,
+.Nm archive_read_set_options
+.Nd functions controlling options for reading archives
+.\"
+.Sh SYNOPSIS
+.Ft int
+.Fo archive_read_set_filter_option
+.Fa "struct archive *"
+.Fa "const char *module"
+.Fa "const char *option"
+.Fa "const char *value"
+.Fc
+.Ft int
+.Fo archive_read_set_format_option
+.Fa "struct archive *"
+.Fa "const char *module"
+.Fa "const char *option"
+.Fa "const char *value"
+.Fc
+.Ft int
+.Fo archive_read_set_option
+.Fa "struct archive *"
+.Fa "const char *module"
+.Fa "const char *option"
+.Fa "const char *value"
+.Fc
+.Ft int
+.Fo archive_read_set_options
+.Fa "struct archive *"
+.Fa "const char *options"
+.Fc
+.Sh DESCRIPTION
+These functions provide a way for libarchive clients to configure
+specific read modules.
+.Bl -tag -width indent
+.It Xo
+.Fn archive_read_set_filter_option ,
+.Fn archive_read_set_format_option
+.Xc
+Specifies an option that will be passed to currently-registered
+filters (including decompression filters) or format readers.
+.Pp
+If
+.Ar option
+and
+.Ar value
+are both
+.Dv NULL ,
+these functions will do nothing and
+.Cm ARCHIVE_OK
+will be returned.
+If
+.Ar option
+is
+.Dv NULL
+but
+.Ar value
+is not, these functions will do nothing and
+.Cm ARCHIVE_FAILED
+will be returned.
+.Pp
+If
+.Ar module
+is not
+.Dv NULL ,
+.Ar option
+and
+.Ar value
+will be provided to the filter or reader named
+.Ar module .
+The return value will be that of the module.
+If there is no such module,
+.Cm ARCHIVE_FAILED
+will be returned.
+.Pp
+If
+.Ar module
+is
+.Dv NULL ,
+.Ar option
+and
+.Ar value
+will be provided to every registered module.
+If any module returns
+.Cm ARCHIVE_FATAL ,
+this value will be returned immediately.
+Otherwise,
+.Cm ARCHIVE_OK
+will be returned if any module accepts the option, and
+.Cm ARCHIVE_FAILED
+in all other cases.
+.\"
+.It Xo
+.Fn archive_read_set_option
+.Xc
+Calls
+.Fn archive_read_set_format_option ,
+then
+.Fn archive_read_set_filter_option .
+If either function returns
+.Cm ARCHIVE_FATAL ,
+.Cm ARCHIVE_FATAL
+will be returned
+immediately.
+Otherwise, greater of the two values will be returned.
+.\"
+.It Xo
+.Fn archive_read_set_options
+.Xc
+.Ar options
+is a comma-separated list of options.
+If
+.Ar options
+is
+.Dv NULL
+or empty,
+.Cm ARCHIVE_OK
+will be returned immediately.
+.Pp
+Calls
+.Fn archive_read_set_option
+with each option in turn.
+If any
+.Fn archive_read_set_option
+call returns
+.Cm ARCHIVE_FATAL ,
+.Cm ARCHIVE_FATAL
+will be returned immediately.
+.Pp
+Individual options have one of the following forms:
+.Bl -tag -compact -width indent
+.It Ar option=value
+The option/value pair will be provided to every module.
+Modules that do not accept an option with this name will ignore it.
+.It Ar option
+The option will be provided to every module with a value of
+.Dq 1 .
+.It Ar !option
+The option will be provided to every module with a NULL value.
+.It Ar module:option=value , Ar module:option , Ar module:!option
+As above, but the corresponding option and value will be provided
+only to modules whose name matches
+.Ar module .
+.El
+.El
+.\"
+.Sh OPTIONS
+.Bl -tag -compact -width indent
+.It Format iso9660
+.Bl -tag -compact -width indent
+.It Cm joliet
+Support Joliet extensions.
+Defaults to enabled, use
+.Cm !joliet
+to disable.
+.It Cm rockridge
+Support RockRidge extensions.
+Defaults to enabled, use
+.Cm !rockridge
+to disable.
+.El
+.El
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_write_set_options 3 ,
+.Xr archive_read 3
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_set_options.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_set_options.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2011 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive_read_private.h"
+#include "archive_options_private.h"
+
+static int archive_set_format_option(struct archive *a,
+ const char *m, const char *o, const char *v);
+static int archive_set_filter_option(struct archive *a,
+ const char *m, const char *o, const char *v);
+static int archive_set_option(struct archive *a,
+ const char *m, const char *o, const char *v);
+
+int
+archive_read_set_format_option(struct archive *a, const char *m, const char *o,
+ const char *v)
+{
+ return _archive_set_option(a, m, o, v,
+ ARCHIVE_READ_MAGIC, "archive_read_set_format_option",
+ archive_set_format_option);
+}
+
+int
+archive_read_set_filter_option(struct archive *a, const char *m, const char *o,
+ const char *v)
+{
+ return _archive_set_option(a, m, o, v,
+ ARCHIVE_READ_MAGIC, "archive_read_set_filter_option",
+ archive_set_filter_option);
+}
+
+int
+archive_read_set_option(struct archive *a, const char *m, const char *o,
+ const char *v)
+{
+ return _archive_set_option(a, m, o, v,
+ ARCHIVE_READ_MAGIC, "archive_read_set_option",
+ archive_set_option);
+}
+
+int
+archive_read_set_options(struct archive *a, const char *options)
+{
+ return _archive_set_options(a, options,
+ ARCHIVE_READ_MAGIC, "archive_read_set_options",
+ archive_set_option);
+}
+
+static int
+archive_set_format_option(struct archive *_a, const char *m, const char *o,
+ const char *v)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_format_descriptor *format;
+ size_t i;
+ int r, rv = ARCHIVE_WARN;
+
+ for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) {
+ format = &a->formats[i];
+ if (format == NULL || format->options == NULL ||
+ format->name == NULL)
+ /* This format does not support option. */
+ continue;
+ if (m != NULL && strcmp(format->name, m) != 0)
+ continue;
+
+ a->format = format;
+ r = format->options(a, o, v);
+ a->format = NULL;
+
+ if (r == ARCHIVE_FATAL)
+ return (ARCHIVE_FATAL);
+
+ if (m != NULL)
+ return (r);
+
+ if (r == ARCHIVE_OK)
+ rv = ARCHIVE_OK;
+ }
+ /* If the format name didn't match, return a special code for
+ * _archive_set_option[s]. */
+ if (rv == ARCHIVE_WARN && m != NULL)
+ rv = ARCHIVE_WARN - 1;
+ return (rv);
+}
+
+static int
+archive_set_filter_option(struct archive *_a, const char *m, const char *o,
+ const char *v)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter *filter;
+ struct archive_read_filter_bidder *bidder;
+ int r, rv = ARCHIVE_WARN;
+
+ for (filter = a->filter; filter != NULL; filter = filter->upstream) {
+ bidder = filter->bidder;
+ if (bidder == NULL)
+ continue;
+ if (bidder->options == NULL)
+ /* This bidder does not support option */
+ continue;
+ if (m != NULL && strcmp(filter->name, m) != 0)
+ continue;
+
+ r = bidder->options(bidder, o, v);
+
+ if (r == ARCHIVE_FATAL)
+ return (ARCHIVE_FATAL);
+
+ if (m != NULL)
+ return (r);
+
+ if (r == ARCHIVE_OK)
+ rv = ARCHIVE_OK;
+ }
+ /* If the filter name didn't match, return a special code for
+ * _archive_set_option[s]. */
+ if (rv == ARCHIVE_WARN && m != NULL)
+ rv = ARCHIVE_WARN - 1;
+ return (rv);
+}
+
+static int
+archive_set_option(struct archive *a, const char *m, const char *o,
+ const char *v)
+{
+ return _archive_set_either_option(a, m, o, v,
+ archive_set_format_option,
+ archive_set_filter_option);
+}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_compression_all.c
--- a/head/contrib/libarchive/libarchive/archive_read_support_compression_all.c Fri Mar 02 16:58:39 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/contrib/libarchive/libarchive/archive_read_support_compression_all.c 228763 2011-12-21 11:13:29Z mm $");
-
-#include "archive.h"
-
-int
-archive_read_support_compression_all(struct archive *a)
-{
- /* Bzip falls back to "bunzip2" command-line */
- archive_read_support_compression_bzip2(a);
- /* The decompress code doesn't use an outside library. */
- archive_read_support_compression_compress(a);
- /* Gzip decompress falls back to "gunzip" command-line. */
- archive_read_support_compression_gzip(a);
- /* The LZMA file format has a very weak signature, so it
- * may not be feasible to keep this here, but we'll try.
- * This will come back out if there are problems. */
- /* Lzma falls back to "unlzma" command-line program. */
- archive_read_support_compression_lzma(a);
- /* Xz falls back to "unxz" command-line program. */
- archive_read_support_compression_xz(a);
- /* The decode code doesn't use an outside library. */
- archive_read_support_compression_uu(a);
- /* The decode code doesn't use an outside library. */
- archive_read_support_compression_rpm(a);
-
- /* Note: We always return ARCHIVE_OK here, even if some of the
- * above return ARCHIVE_WARN. The intent here is to enable
- * "as much as possible." Clients who need specific
- * compression should enable those individually so they can
- * verify the level of support. */
- /* Clear any warning messages set by the above functions. */
- archive_clear_error(a);
- return (ARCHIVE_OK);
-}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_compression_bzip2.c
--- a/head/contrib/libarchive/libarchive/archive_read_support_compression_bzip2.c Fri Mar 02 16:58:39 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,353 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-
-__FBSDID("$FreeBSD: head/contrib/libarchive/libarchive/archive_read_support_compression_bzip2.c 228763 2011-12-21 11:13:29Z mm $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_BZLIB_H
-#include <bzlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
-struct private_data {
- bz_stream stream;
- char *out_block;
- size_t out_block_size;
- char valid; /* True = decompressor is initialized */
- char eof; /* True = found end of compressed data. */
-};
-
-/* Bzip2 filter */
-static ssize_t bzip2_filter_read(struct archive_read_filter *, const void **);
-static int bzip2_filter_close(struct archive_read_filter *);
-#endif
-
-/*
- * Note that we can detect bzip2 archives even if we can't decompress
- * them. (In fact, we like detecting them because we can give better
- * error messages.) So the bid framework here gets compiled even
- * if bzlib is unavailable.
- */
-static int bzip2_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
-static int bzip2_reader_init(struct archive_read_filter *);
-static int bzip2_reader_free(struct archive_read_filter_bidder *);
-
-int
-archive_read_support_compression_bzip2(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *reader = __archive_read_get_bidder(a);
-
- if (reader == NULL)
- return (ARCHIVE_FATAL);
-
- reader->data = NULL;
- reader->bid = bzip2_reader_bid;
- reader->init = bzip2_reader_init;
- reader->options = NULL;
- reader->free = bzip2_reader_free;
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- return (ARCHIVE_OK);
-#else
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "Using external bunzip2 program");
- return (ARCHIVE_WARN);
-#endif
-}
-
-static int
-bzip2_reader_free(struct archive_read_filter_bidder *self){
- (void)self; /* UNUSED */
- return (ARCHIVE_OK);
-}
-
-/*
- * Test whether we can handle this data.
- *
- * This logic returns zero if any part of the signature fails. It
- * also tries to Do The Right Thing if a very short buffer prevents us
- * from verifying as much as we would like.
- */
-static int
-bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_filter *filter)
-{
- const unsigned char *buffer;
- ssize_t avail;
- int bits_checked;
-
- (void)self; /* UNUSED */
-
- /* Minimal bzip2 archive is 14 bytes. */
- buffer = __archive_read_filter_ahead(filter, 14, &avail);
- if (buffer == NULL)
- return (0);
-
- /* First three bytes must be "BZh" */
- bits_checked = 0;
- if (buffer[0] != 'B' || buffer[1] != 'Z' || buffer[2] != 'h')
- return (0);
- bits_checked += 24;
-
- /* Next follows a compression flag which must be an ASCII digit. */
- if (buffer[3] < '1' || buffer[3] > '9')
- return (0);
- bits_checked += 5;
-
- /* After BZh[1-9], there must be either a data block
- * which begins with 0x314159265359 or an end-of-data
- * marker of 0x177245385090. */
- if (memcmp(buffer + 4, "\x31\x41\x59\x26\x53\x59", 6) == 0)
- bits_checked += 48;
- else if (memcmp(buffer + 4, "\x17\x72\x45\x38\x50\x90", 6) == 0)
- bits_checked += 48;
- else
- return (0);
-
- return (bits_checked);
-}
-
-#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
-
-/*
- * If we don't have the library on this system, we can't actually do the
- * decompression. We can, however, still detect compressed archives
- * and emit a useful message.
- */
-static int
-bzip2_reader_init(struct archive_read_filter *self)
-{
- int r;
-
- r = __archive_read_program(self, "bunzip2");
- /* Note: We set the format here even if __archive_read_program()
- * above fails. We do, after all, know what the format is
- * even if we weren't able to read it. */
- self->code = ARCHIVE_COMPRESSION_BZIP2;
- self->name = "bzip2";
- return (r);
-}
-
-
-#else
-
-/*
- * Setup the callbacks.
- */
-static int
-bzip2_reader_init(struct archive_read_filter *self)
-{
- static const size_t out_block_size = 64 * 1024;
- void *out_block;
- struct private_data *state;
-
- self->code = ARCHIVE_COMPRESSION_BZIP2;
- self->name = "bzip2";
-
- state = (struct private_data *)calloc(sizeof(*state), 1);
- out_block = (unsigned char *)malloc(out_block_size);
- if (self == NULL || state == NULL || out_block == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for bzip2 decompression");
- free(out_block);
- free(state);
- return (ARCHIVE_FATAL);
- }
-
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->read = bzip2_filter_read;
- self->skip = NULL; /* not supported */
- self->close = bzip2_filter_close;
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Return the next block of decompressed data.
- */
-static ssize_t
-bzip2_filter_read(struct archive_read_filter *self, const void **p)
-{
- struct private_data *state;
- size_t decompressed;
- const char *read_buf;
- ssize_t ret;
-
- state = (struct private_data *)self->data;
-
- if (state->eof) {
- *p = NULL;
- return (0);
- }
-
- /* Empty our output buffer. */
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
-
- /* Try to fill the output buffer. */
- for (;;) {
- if (!state->valid) {
- if (bzip2_reader_bid(self->bidder, self->upstream) == 0) {
- state->eof = 1;
- *p = state->out_block;
- decompressed = state->stream.next_out
- - state->out_block;
- return (decompressed);
- }
- /* Initialize compression library. */
- ret = BZ2_bzDecompressInit(&(state->stream),
- 0 /* library verbosity */,
- 0 /* don't use low-mem algorithm */);
-
- /* If init fails, try low-memory algorithm instead. */
- if (ret == BZ_MEM_ERROR)
- ret = BZ2_bzDecompressInit(&(state->stream),
- 0 /* library verbosity */,
- 1 /* do use low-mem algo */);
-
- if (ret != BZ_OK) {
- const char *detail = NULL;
- int err = ARCHIVE_ERRNO_MISC;
- switch (ret) {
- case BZ_PARAM_ERROR:
- detail = "invalid setup parameter";
- break;
- case BZ_MEM_ERROR:
- err = ENOMEM;
- detail = "out of memory";
- break;
- case BZ_CONFIG_ERROR:
- detail = "mis-compiled library";
- break;
- }
- archive_set_error(&self->archive->archive, err,
- "Internal error initializing decompressor%s%s",
- detail == NULL ? "" : ": ",
- detail);
- return (ARCHIVE_FATAL);
- }
- state->valid = 1;
- }
-
- /* stream.next_in is really const, but bzlib
- * doesn't declare it so. <sigh> */
- read_buf =
- __archive_read_filter_ahead(self->upstream, 1, &ret);
- if (read_buf == NULL)
- return (ARCHIVE_FATAL);
- state->stream.next_in = (char *)(uintptr_t)read_buf;
- state->stream.avail_in = ret;
- /* There is no more data, return whatever we have. */
- if (ret == 0) {
- state->eof = 1;
- *p = state->out_block;
- decompressed = state->stream.next_out
- - state->out_block;
- return (decompressed);
- }
-
- /* Decompress as much as we can in one pass. */
- ret = BZ2_bzDecompress(&(state->stream));
- __archive_read_filter_consume(self->upstream,
- state->stream.next_in - read_buf);
-
- switch (ret) {
- case BZ_STREAM_END: /* Found end of stream. */
- switch (BZ2_bzDecompressEnd(&(state->stream))) {
- case BZ_OK:
- break;
- default:
- archive_set_error(&(self->archive->archive),
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up decompressor");
- return (ARCHIVE_FATAL);
- }
- state->valid = 0;
- /* FALLTHROUGH */
- case BZ_OK: /* Decompressor made some progress. */
- /* If we filled our buffer, update stats and return. */
- if (state->stream.avail_out == 0) {
- *p = state->out_block;
- decompressed = state->stream.next_out
- - state->out_block;
- return (decompressed);
- }
- break;
- default: /* Return an error. */
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC, "bzip decompression failed");
- return (ARCHIVE_FATAL);
- }
- }
-}
-
-/*
- * Clean up the decompressor.
- */
-static int
-bzip2_filter_close(struct archive_read_filter *self)
-{
- struct private_data *state;
- int ret = ARCHIVE_OK;
-
- state = (struct private_data *)self->data;
-
- if (state->valid) {
- switch (BZ2_bzDecompressEnd(&state->stream)) {
- case BZ_OK:
- break;
- default:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up decompressor");
- ret = ARCHIVE_FATAL;
- }
- }
-
- free(state->out_block);
- free(state);
- return (ret);
-}
-
-#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_compression_compress.c
--- a/head/contrib/libarchive/libarchive/archive_read_support_compression_compress.c Fri Mar 02 16:58:39 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,444 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * This code borrows heavily from "compress" source code, which is
- * protected by the following copyright. (Clause 3 dropped by request
- * of the Regents.)
- */
-
-/*-
- * Copyright (c) 1985, 1986, 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Diomidis Spinellis and James A. Woods, derived from original
- * work by Spencer Thomas and Joseph Orost.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/contrib/libarchive/libarchive/archive_read_support_compression_compress.c 228763 2011-12-21 11:13:29Z mm $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-/*
- * Because LZW decompression is pretty simple, I've just implemented
- * the whole decompressor here (cribbing from "compress" source code,
- * of course), rather than relying on an external library. I have
- * made an effort to clarify and simplify the algorithm, so the
- * names and structure here don't exactly match those used by compress.
- */
-
-struct private_data {
- /* Input variables. */
- const unsigned char *next_in;
- size_t avail_in;
- int bit_buffer;
- int bits_avail;
- size_t bytes_in_section;
-
- /* Output variables. */
- size_t out_block_size;
- void *out_block;
-
- /* Decompression status variables. */
- int use_reset_code;
- int end_of_stream; /* EOF status. */
- int maxcode; /* Largest code. */
- int maxcode_bits; /* Length of largest code. */
- int section_end_code; /* When to increase bits. */
- int bits; /* Current code length. */
- int oldcode; /* Previous code. */
- int finbyte; /* Last byte of prev code. */
-
- /* Dictionary. */
- int free_ent; /* Next dictionary entry. */
- unsigned char suffix[65536];
- uint16_t prefix[65536];
-
- /*
- * Scratch area for expanding dictionary entries. Note:
- * "worst" case here comes from compressing /dev/zero: the
- * last code in the dictionary will code a sequence of
- * 65536-256 zero bytes. Thus, we need stack space to expand
- * a 65280-byte dictionary entry. (Of course, 32640:1
- * compression could also be considered the "best" case. ;-)
- */
- unsigned char *stackp;
- unsigned char stack[65300];
-};
-
-static int compress_bidder_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
-static int compress_bidder_init(struct archive_read_filter *);
-static int compress_bidder_free(struct archive_read_filter_bidder *);
-
-static ssize_t compress_filter_read(struct archive_read_filter *, const void **);
-static int compress_filter_close(struct archive_read_filter *);
-
-static int getbits(struct archive_read_filter *, int n);
-static int next_code(struct archive_read_filter *);
-
-int
-archive_read_support_compression_compress(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *bidder = __archive_read_get_bidder(a);
-
- if (bidder == NULL)
- return (ARCHIVE_FATAL);
-
- bidder->data = NULL;
- bidder->bid = compress_bidder_bid;
- bidder->init = compress_bidder_init;
- bidder->options = NULL;
- bidder->free = compress_bidder_free;
- return (ARCHIVE_OK);
-}
-
-/*
- * Test whether we can handle this data.
- *
- * This logic returns zero if any part of the signature fails. It
- * also tries to Do The Right Thing if a very short buffer prevents us
- * from verifying as much as we would like.
- */
-static int
-compress_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- const unsigned char *buffer;
- ssize_t avail;
- int bits_checked;
-
- (void)self; /* UNUSED */
-
- buffer = __archive_read_filter_ahead(filter, 2, &avail);
-
- if (buffer == NULL)
- return (0);
-
- bits_checked = 0;
- if (buffer[0] != 037) /* Verify first ID byte. */
- return (0);
- bits_checked += 8;
-
- if (buffer[1] != 0235) /* Verify second ID byte. */
- return (0);
- bits_checked += 8;
-
- /*
- * TODO: Verify more.
- */
-
- return (bits_checked);
-}
-
-/*
- * Setup the callbacks.
- */
-static int
-compress_bidder_init(struct archive_read_filter *self)
-{
- struct private_data *state;
- static const size_t out_block_size = 64 * 1024;
- void *out_block;
- int code;
-
- self->code = ARCHIVE_COMPRESSION_COMPRESS;
- self->name = "compress (.Z)";
-
- state = (struct private_data *)calloc(sizeof(*state), 1);
- out_block = malloc(out_block_size);
- if (state == NULL || out_block == NULL) {
- free(out_block);
- free(state);
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for %s decompression",
- self->name);
- return (ARCHIVE_FATAL);
- }
-
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->read = compress_filter_read;
- self->skip = NULL; /* not supported */
- self->close = compress_filter_close;
-
- /* XXX MOVE THE FOLLOWING OUT OF INIT() XXX */
-
- (void)getbits(self, 8); /* Skip first signature byte. */
- (void)getbits(self, 8); /* Skip second signature byte. */
-
- code = getbits(self, 8);
- state->maxcode_bits = code & 0x1f;
- state->maxcode = (1 << state->maxcode_bits);
- state->use_reset_code = code & 0x80;
-
- /* Initialize decompressor. */
- state->free_ent = 256;
- state->stackp = state->stack;
- if (state->use_reset_code)
- state->free_ent++;
- state->bits = 9;
- state->section_end_code = (1<<state->bits) - 1;
- state->oldcode = -1;
- for (code = 255; code >= 0; code--) {
- state->prefix[code] = 0;
- state->suffix[code] = code;
- }
- next_code(self);
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Return a block of data from the decompression buffer. Decompress more
- * as necessary.
- */
-static ssize_t
-compress_filter_read(struct archive_read_filter *self, const void **pblock)
-{
- struct private_data *state;
- unsigned char *p, *start, *end;
- int ret;
-
- state = (struct private_data *)self->data;
- if (state->end_of_stream) {
- *pblock = NULL;
- return (0);
- }
- p = start = (unsigned char *)state->out_block;
- end = start + state->out_block_size;
-
- while (p < end && !state->end_of_stream) {
- if (state->stackp > state->stack) {
- *p++ = *--state->stackp;
- } else {
- ret = next_code(self);
- if (ret == -1)
- state->end_of_stream = ret;
- else if (ret != ARCHIVE_OK)
- return (ret);
- }
- }
-
- *pblock = start;
- return (p - start);
-}
-
-/*
- * Clean up the reader.
- */
-static int
-compress_bidder_free(struct archive_read_filter_bidder *self)
-{
- self->data = NULL;
- return (ARCHIVE_OK);
-}
-
-/*
- * Close and release the filter.
- */
-static int
-compress_filter_close(struct archive_read_filter *self)
-{
- struct private_data *state = (struct private_data *)self->data;
-
- free(state->out_block);
- free(state);
- return (ARCHIVE_OK);
-}
-
-/*
- * Process the next code and fill the stack with the expansion
- * of the code. Returns ARCHIVE_FATAL if there is a fatal I/O or
- * format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.
- */
-static int
-next_code(struct archive_read_filter *self)
-{
- struct private_data *state = (struct private_data *)self->data;
- int code, newcode;
-
- static int debug_buff[1024];
- static unsigned debug_index;
-
- code = newcode = getbits(self, state->bits);
- if (code < 0)
- return (code);
-
- debug_buff[debug_index++] = code;
- if (debug_index >= sizeof(debug_buff)/sizeof(debug_buff[0]))
- debug_index = 0;
-
- /* If it's a reset code, reset the dictionary. */
- if ((code == 256) && state->use_reset_code) {
- /*
- * The original 'compress' implementation blocked its
- * I/O in a manner that resulted in junk bytes being
- * inserted after every reset. The next section skips
- * this junk. (Yes, the number of *bytes* to skip is
- * a function of the current *bit* length.)
- */
- int skip_bytes = state->bits -
- (state->bytes_in_section % state->bits);
- skip_bytes %= state->bits;
- state->bits_avail = 0; /* Discard rest of this byte. */
- while (skip_bytes-- > 0) {
- code = getbits(self, 8);
- if (code < 0)
- return (code);
- }
- /* Now, actually do the reset. */
- state->bytes_in_section = 0;
- state->bits = 9;
- state->section_end_code = (1 << state->bits) - 1;
- state->free_ent = 257;
- state->oldcode = -1;
- return (next_code(self));
- }
-
- if (code > state->free_ent) {
- /* An invalid code is a fatal error. */
- archive_set_error(&(self->archive->archive), -1,
- "Invalid compressed data");
- return (ARCHIVE_FATAL);
- }
-
- /* Special case for KwKwK string. */
- if (code >= state->free_ent) {
- *state->stackp++ = state->finbyte;
- code = state->oldcode;
- }
-
- /* Generate output characters in reverse order. */
- while (code >= 256) {
- *state->stackp++ = state->suffix[code];
- code = state->prefix[code];
- }
- *state->stackp++ = state->finbyte = code;
-
- /* Generate the new entry. */
- code = state->free_ent;
- if (code < state->maxcode && state->oldcode >= 0) {
- state->prefix[code] = state->oldcode;
- state->suffix[code] = state->finbyte;
- ++state->free_ent;
- }
- if (state->free_ent > state->section_end_code) {
- state->bits++;
- state->bytes_in_section = 0;
- if (state->bits == state->maxcode_bits)
- state->section_end_code = state->maxcode;
- else
- state->section_end_code = (1 << state->bits) - 1;
- }
-
- /* Remember previous code. */
- state->oldcode = newcode;
- return (ARCHIVE_OK);
-}
-
-/*
- * Return next 'n' bits from stream.
- *
- * -1 indicates end of available data.
- */
-static int
-getbits(struct archive_read_filter *self, int n)
-{
- struct private_data *state = (struct private_data *)self->data;
- int code;
- ssize_t ret;
- static const int mask[] = {
- 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
- 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff
- };
-
- while (state->bits_avail < n) {
- if (state->avail_in <= 0) {
- state->next_in
- = __archive_read_filter_ahead(self->upstream,
- 1, &ret);
- if (ret == 0)
- return (-1);
- if (ret < 0 || state->next_in == NULL)
- return (ARCHIVE_FATAL);
- state->avail_in = ret;
- __archive_read_filter_consume(self->upstream, ret);
- }
- state->bit_buffer |= *state->next_in++ << state->bits_avail;
- state->avail_in--;
- state->bits_avail += 8;
- state->bytes_in_section++;
- }
-
- code = state->bit_buffer;
- state->bit_buffer >>= n;
- state->bits_avail -= n;
-
- return (code & mask[n]);
-}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_compression_gzip.c
--- a/head/contrib/libarchive/libarchive/archive_read_support_compression_gzip.c Fri Mar 02 16:58:39 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,465 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-
-__FBSDID("$FreeBSD: head/contrib/libarchive/libarchive/archive_read_support_compression_gzip.c 228763 2011-12-21 11:13:29Z mm $");
-
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-#ifdef HAVE_ZLIB_H
-struct private_data {
- z_stream stream;
- char in_stream;
- unsigned char *out_block;
- size_t out_block_size;
- int64_t total_out;
- unsigned long crc;
- char eof; /* True = found end of compressed data. */
-};
-
-/* Gzip Filter. */
-static ssize_t gzip_filter_read(struct archive_read_filter *, const void **);
-static int gzip_filter_close(struct archive_read_filter *);
-#endif
-
-/*
- * Note that we can detect gzip archives even if we can't decompress
- * them. (In fact, we like detecting them because we can give better
- * error messages.) So the bid framework here gets compiled even
- * if zlib is unavailable.
- *
- * TODO: If zlib is unavailable, gzip_bidder_init() should
- * use the compress_program framework to try to fire up an external
- * gunzip program.
- */
-static int gzip_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *);
-static int gzip_bidder_init(struct archive_read_filter *);
-
-int
-archive_read_support_compression_gzip(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *bidder = __archive_read_get_bidder(a);
-
- if (bidder == NULL)
- return (ARCHIVE_FATAL);
-
- bidder->data = NULL;
- bidder->bid = gzip_bidder_bid;
- bidder->init = gzip_bidder_init;
- bidder->options = NULL;
- bidder->free = NULL; /* No data, so no cleanup necessary. */
- /* Signal the extent of gzip support with the return value here. */
-#if HAVE_ZLIB_H
- return (ARCHIVE_OK);
-#else
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "Using external gunzip program");
- return (ARCHIVE_WARN);
-#endif
-}
-
-/*
- * Read and verify the header.
- *
- * Returns zero if the header couldn't be validated, else returns
- * number of bytes in header. If pbits is non-NULL, it receives a
- * count of bits verified, suitable for use by bidder.
- */
-static int
-peek_at_header(struct archive_read_filter *filter, int *pbits)
-{
- const unsigned char *p;
- ssize_t avail, len;
- int bits = 0;
- int header_flags;
-
- /* Start by looking at the first ten bytes of the header, which
- * is all fixed layout. */
- len = 10;
- p = __archive_read_filter_ahead(filter, len, &avail);
- if (p == NULL || avail == 0)
- return (0);
- if (p[0] != 037)
- return (0);
- bits += 8;
- if (p[1] != 0213)
- return (0);
- bits += 8;
- if (p[2] != 8) /* We only support deflation. */
- return (0);
- bits += 8;
- if ((p[3] & 0xE0)!= 0) /* No reserved flags set. */
- return (0);
- bits += 3;
- header_flags = p[3];
- /* Bytes 4-7 are mod time. */
- /* Byte 8 is deflate flags. */
- /* XXXX TODO: return deflate flags back to consume_header for use
- in initializing the decompressor. */
- /* Byte 9 is OS. */
-
- /* Optional extra data: 2 byte length plus variable body. */
- if (header_flags & 4) {
- p = __archive_read_filter_ahead(filter, len + 2, &avail);
- if (p == NULL)
- return (0);
- len += ((int)p[len + 1] << 8) | (int)p[len];
- len += 2;
- }
-
- /* Null-terminated optional filename. */
- if (header_flags & 8) {
- do {
- ++len;
- if (avail < len)
- p = __archive_read_filter_ahead(filter,
- len, &avail);
- if (p == NULL)
- return (0);
- } while (p[len - 1] != 0);
- }
-
- /* Null-terminated optional comment. */
- if (header_flags & 16) {
- do {
- ++len;
- if (avail < len)
- p = __archive_read_filter_ahead(filter,
- len, &avail);
- if (p == NULL)
- return (0);
- } while (p[len - 1] != 0);
- }
-
- /* Optional header CRC */
- if ((header_flags & 2)) {
- p = __archive_read_filter_ahead(filter, len + 2, &avail);
- if (p == NULL)
- return (0);
-#if 0
- int hcrc = ((int)p[len + 1] << 8) | (int)p[len];
- int crc = /* XXX TODO: Compute header CRC. */;
- if (crc != hcrc)
- return (0);
- bits += 16;
-#endif
- len += 2;
- }
-
- if (pbits != NULL)
- *pbits = bits;
- return (len);
-}
-
-/*
- * Bidder just verifies the header and returns the number of verified bits.
- */
-static int
-gzip_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- int bits_checked;
-
- (void)self; /* UNUSED */
-
- if (peek_at_header(filter, &bits_checked))
- return (bits_checked);
- return (0);
-}
-
-
-#ifndef HAVE_ZLIB_H
-
-/*
- * If we don't have the library on this system, we can't do the
- * decompression directly. We can, however, try to run gunzip
- * in case that's available.
- */
-static int
-gzip_bidder_init(struct archive_read_filter *self)
-{
- int r;
-
- r = __archive_read_program(self, "gunzip");
- /* Note: We set the format here even if __archive_read_program()
- * above fails. We do, after all, know what the format is
- * even if we weren't able to read it. */
- self->code = ARCHIVE_COMPRESSION_GZIP;
- self->name = "gzip";
- return (r);
-}
-
-#else
-
-/*
- * Initialize the filter object.
- */
-static int
-gzip_bidder_init(struct archive_read_filter *self)
-{
- struct private_data *state;
- static const size_t out_block_size = 64 * 1024;
- void *out_block;
-
- self->code = ARCHIVE_COMPRESSION_GZIP;
- self->name = "gzip";
-
- state = (struct private_data *)calloc(sizeof(*state), 1);
- out_block = (unsigned char *)malloc(out_block_size);
- if (state == NULL || out_block == NULL) {
- free(out_block);
- free(state);
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for gzip decompression");
- return (ARCHIVE_FATAL);
- }
-
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->read = gzip_filter_read;
- self->skip = NULL; /* not supported */
- self->close = gzip_filter_close;
-
- state->in_stream = 0; /* We're not actually within a stream yet. */
-
- return (ARCHIVE_OK);
-}
-
-static int
-consume_header(struct archive_read_filter *self)
-{
- struct private_data *state;
- ssize_t avail;
- size_t len;
- int ret;
-
- state = (struct private_data *)self->data;
-
- /* If this is a real header, consume it. */
- len = peek_at_header(self->upstream, NULL);
- if (len == 0)
- return (ARCHIVE_EOF);
- __archive_read_filter_consume(self->upstream, len);
-
- /* Initialize CRC accumulator. */
- state->crc = crc32(0L, NULL, 0);
-
- /* Initialize compression library. */
- state->stream.next_in = (unsigned char *)(uintptr_t)
- __archive_read_filter_ahead(self->upstream, 1, &avail);
- state->stream.avail_in = avail;
- ret = inflateInit2(&(state->stream),
- -15 /* Don't check for zlib header */);
-
- /* Decipher the error code. */
- switch (ret) {
- case Z_OK:
- state->in_stream = 1;
- return (ARCHIVE_OK);
- case Z_STREAM_ERROR:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "invalid setup parameter");
- break;
- case Z_MEM_ERROR:
- archive_set_error(&self->archive->archive, ENOMEM,
- "Internal error initializing compression library: "
- "out of memory");
- break;
- case Z_VERSION_ERROR:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "invalid library version");
- break;
- default:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- " Zlib error %d", ret);
- break;
- }
- return (ARCHIVE_FATAL);
-}
-
-static int
-consume_trailer(struct archive_read_filter *self)
-{
- struct private_data *state;
- const unsigned char *p;
- ssize_t avail;
-
- state = (struct private_data *)self->data;
-
- state->in_stream = 0;
- switch (inflateEnd(&(state->stream))) {
- case Z_OK:
- break;
- default:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up gzip decompressor");
- return (ARCHIVE_FATAL);
- }
-
- /* GZip trailer is a fixed 8 byte structure. */
- p = __archive_read_filter_ahead(self->upstream, 8, &avail);
- if (p == NULL || avail == 0)
- return (ARCHIVE_FATAL);
-
- /* XXX TODO: Verify the length and CRC. */
-
- /* We've verified the trailer, so consume it now. */
- __archive_read_filter_consume(self->upstream, 8);
-
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-gzip_filter_read(struct archive_read_filter *self, const void **p)
-{
- struct private_data *state;
- size_t decompressed;
- ssize_t avail_in;
- int ret;
-
- state = (struct private_data *)self->data;
-
- /* Empty our output buffer. */
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
-
- /* Try to fill the output buffer. */
- while (state->stream.avail_out > 0 && !state->eof) {
- /* If we're not in a stream, read a header
- * and initialize the decompression library. */
- if (!state->in_stream) {
- ret = consume_header(self);
- if (ret == ARCHIVE_EOF) {
- state->eof = 1;
- break;
- }
- if (ret < ARCHIVE_OK)
- return (ret);
- }
-
- /* Peek at the next available data. */
- /* ZLib treats stream.next_in as const but doesn't declare
- * it so, hence this ugly cast. */
- state->stream.next_in = (unsigned char *)(uintptr_t)
- __archive_read_filter_ahead(self->upstream, 1, &avail_in);
- if (state->stream.next_in == NULL)
- return (ARCHIVE_FATAL);
- state->stream.avail_in = avail_in;
-
- /* Decompress and consume some of that data. */
- ret = inflate(&(state->stream), 0);
- switch (ret) {
- case Z_OK: /* Decompressor made some progress. */
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
- break;
- case Z_STREAM_END: /* Found end of stream. */
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
- /* Consume the stream trailer; release the
- * decompression library. */
- ret = consume_trailer(self);
- if (ret < ARCHIVE_OK)
- return (ret);
- break;
- default:
- /* Return an error. */
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "gzip decompression failed");
- return (ARCHIVE_FATAL);
- }
- }
-
- /* We've read as much as we can. */
- decompressed = state->stream.next_out - state->out_block;
- state->total_out += decompressed;
- if (decompressed == 0)
- *p = NULL;
- else
- *p = state->out_block;
- return (decompressed);
-}
-
-/*
- * Clean up the decompressor.
- */
-static int
-gzip_filter_close(struct archive_read_filter *self)
-{
- struct private_data *state;
- int ret;
-
- state = (struct private_data *)self->data;
- ret = ARCHIVE_OK;
-
- if (state->in_stream) {
- switch (inflateEnd(&(state->stream))) {
- case Z_OK:
- break;
- default:
- archive_set_error(&(self->archive->archive),
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up gzip compressor");
- ret = ARCHIVE_FATAL;
- }
- }
-
- free(state->out_block);
- free(state);
- return (ret);
-}
-
-#endif /* HAVE_ZLIB_H */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_compression_none.c
--- a/head/contrib/libarchive/libarchive/archive_read_support_compression_none.c Fri Mar 02 16:58:39 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/contrib/libarchive/libarchive/archive_read_support_compression_none.c 228763 2011-12-21 11:13:29Z mm $");
-
-#include "archive.h"
-
-/*
- * Uncompressed streams are handled implicitly by the read core,
- * so this is now a no-op.
- */
-int
-archive_read_support_compression_none(struct archive *a)
-{
- (void)a; /* UNUSED */
- return (ARCHIVE_OK);
-}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_compression_program.c
--- a/head/contrib/libarchive/libarchive/archive_read_support_compression_program.c Fri Mar 02 16:58:39 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,459 +0,0 @@
-/*-
- * Copyright (c) 2007 Joerg Sonnenberger
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/contrib/libarchive/libarchive/archive_read_support_compression_program.c 228763 2011-12-21 11:13:29Z mm $");
-
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-#ifdef HAVE_ERRNO_H
-# include <errno.h>
-#endif
-#ifdef HAVE_FCNTL_H
-# include <fcntl.h>
-#endif
-#ifdef HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#ifdef HAVE_SIGNAL_H
-# include <signal.h>
-#endif
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-int
-archive_read_support_compression_program(struct archive *a, const char *cmd)
-{
- return (archive_read_support_compression_program_signature(a, cmd, NULL, 0));
-}
-
-
-/* This capability is only available on POSIX systems. */
-#if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
- !(defined(HAVE_FORK) || defined(HAVE_VFORK))) && (!defined(_WIN32) || defined(__CYGWIN__))
-
-/*
- * On non-Posix systems, allow the program to build, but choke if
- * this function is actually invoked.
- */
-int
-archive_read_support_compression_program_signature(struct archive *_a,
- const char *cmd, void *signature, size_t signature_len)
-{
- (void)_a; /* UNUSED */
- (void)cmd; /* UNUSED */
- (void)signature; /* UNUSED */
- (void)signature_len; /* UNUSED */
-
- archive_set_error(_a, -1,
- "External compression programs not supported on this platform");
- return (ARCHIVE_FATAL);
-}
-
-int
-__archive_read_program(struct archive_read_filter *self, const char *cmd)
-{
- (void)self; /* UNUSED */
- (void)cmd; /* UNUSED */
-
- archive_set_error(&self->archive->archive, -1,
- "External compression programs not supported on this platform");
- return (ARCHIVE_FATAL);
-}
-
-#else
-
-#include "filter_fork.h"
-
-/*
- * The bidder object stores the command and the signature to watch for.
- * The 'inhibit' entry here is used to ensure that unchecked filters never
- * bid twice in the same pipeline.
- */
-struct program_bidder {
- char *cmd;
- void *signature;
- size_t signature_len;
- int inhibit;
-};
-
-static int program_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *upstream);
-static int program_bidder_init(struct archive_read_filter *);
-static int program_bidder_free(struct archive_read_filter_bidder *);
-
-/*
- * The actual filter needs to track input and output data.
- */
-struct program_filter {
- char *description;
- pid_t child;
- int exit_status;
- int waitpid_return;
- int child_stdin, child_stdout;
-
- char *out_buf;
- size_t out_buf_len;
-};
-
-static ssize_t program_filter_read(struct archive_read_filter *,
- const void **);
-static int program_filter_close(struct archive_read_filter *);
-
-int
-archive_read_support_compression_program_signature(struct archive *_a,
- const char *cmd, const void *signature, size_t signature_len)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *bidder;
- struct program_bidder *state;
-
- /*
- * Get a bidder object from the read core.
- */
- bidder = __archive_read_get_bidder(a);
- if (bidder == NULL)
- return (ARCHIVE_FATAL);
-
- /*
- * Allocate our private state.
- */
- state = (struct program_bidder *)calloc(sizeof (*state), 1);
- if (state == NULL)
- return (ARCHIVE_FATAL);
- state->cmd = strdup(cmd);
- if (signature != NULL && signature_len > 0) {
- state->signature_len = signature_len;
- state->signature = malloc(signature_len);
- memcpy(state->signature, signature, signature_len);
- }
-
- /*
- * Fill in the bidder object.
- */
- bidder->data = state;
- bidder->bid = program_bidder_bid;
- bidder->init = program_bidder_init;
- bidder->options = NULL;
- bidder->free = program_bidder_free;
- return (ARCHIVE_OK);
-}
-
-static int
-program_bidder_free(struct archive_read_filter_bidder *self)
-{
- struct program_bidder *state = (struct program_bidder *)self->data;
- free(state->cmd);
- free(state->signature);
- free(self->data);
- return (ARCHIVE_OK);
-}
-
-/*
- * If we do have a signature, bid only if that matches.
- *
- * If there's no signature, we bid INT_MAX the first time
- * we're called, then never bid again.
- */
-static int
-program_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *upstream)
-{
- struct program_bidder *state = self->data;
- const char *p;
-
- /* If we have a signature, use that to match. */
- if (state->signature_len > 0) {
- p = __archive_read_filter_ahead(upstream,
- state->signature_len, NULL);
- if (p == NULL)
- return (0);
- /* No match, so don't bid. */
- if (memcmp(p, state->signature, state->signature_len) != 0)
- return (0);
- return ((int)state->signature_len * 8);
- }
-
- /* Otherwise, bid once and then never bid again. */
- if (state->inhibit)
- return (0);
- state->inhibit = 1;
- return (INT_MAX);
-}
-
-/*
- * Shut down the child, return ARCHIVE_OK if it exited normally.
- *
- * Note that the return value is sticky; if we're called again,
- * we won't reap the child again, but we will return the same status
- * (including error message if the child came to a bad end).
- */
-static int
-child_stop(struct archive_read_filter *self, struct program_filter *state)
-{
- /* Close our side of the I/O with the child. */
- if (state->child_stdin != -1) {
- close(state->child_stdin);
- state->child_stdin = -1;
- }
- if (state->child_stdout != -1) {
- close(state->child_stdout);
- state->child_stdout = -1;
- }
-
- if (state->child != 0) {
- /* Reap the child. */
- do {
- state->waitpid_return
- = waitpid(state->child, &state->exit_status, 0);
- } while (state->waitpid_return == -1 && errno == EINTR);
- state->child = 0;
- }
-
- if (state->waitpid_return < 0) {
- /* waitpid() failed? This is ugly. */
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
- "Child process exited badly");
- return (ARCHIVE_WARN);
- }
-
-#if !defined(_WIN32) || defined(__CYGWIN__)
- if (WIFSIGNALED(state->exit_status)) {
-#ifdef SIGPIPE
- /* If the child died because we stopped reading before
- * it was done, that's okay. Some archive formats
- * have padding at the end that we routinely ignore. */
- /* The alternative to this would be to add a step
- * before close(child_stdout) above to read from the
- * child until the child has no more to write. */
- if (WTERMSIG(state->exit_status) == SIGPIPE)
- return (ARCHIVE_OK);
-#endif
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
- "Child process exited with signal %d",
- WTERMSIG(state->exit_status));
- return (ARCHIVE_WARN);
- }
-#endif /* !_WIN32 || __CYGWIN__ */
-
- if (WIFEXITED(state->exit_status)) {
- if (WEXITSTATUS(state->exit_status) == 0)
- return (ARCHIVE_OK);
-
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Child process exited with status %d",
- WEXITSTATUS(state->exit_status));
- return (ARCHIVE_WARN);
- }
-
- return (ARCHIVE_WARN);
-}
-
-/*
- * Use select() to decide whether the child is ready for read or write.
- */
-static ssize_t
-child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
-{
- struct program_filter *state = self->data;
- ssize_t ret, requested, avail;
- const char *p;
-
- requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
-
- for (;;) {
- do {
- ret = read(state->child_stdout, buf, requested);
- } while (ret == -1 && errno == EINTR);
-
- if (ret > 0)
- return (ret);
- if (ret == 0 || (ret == -1 && errno == EPIPE))
- /* Child has closed its output; reap the child
- * and return the status. */
- return (child_stop(self, state));
- if (ret == -1 && errno != EAGAIN)
- return (-1);
-
- if (state->child_stdin == -1) {
- /* Block until child has some I/O ready. */
- __archive_check_child(state->child_stdin,
- state->child_stdout);
- continue;
- }
-
- /* Get some more data from upstream. */
- p = __archive_read_filter_ahead(self->upstream, 1, &avail);
- if (p == NULL) {
- close(state->child_stdin);
- state->child_stdin = -1;
- fcntl(state->child_stdout, F_SETFL, 0);
- if (avail < 0)
- return (avail);
- continue;
- }
-
- do {
- ret = write(state->child_stdin, p, avail);
- } while (ret == -1 && errno == EINTR);
-
- if (ret > 0) {
- /* Consume whatever we managed to write. */
- __archive_read_filter_consume(self->upstream, ret);
- } else if (ret == -1 && errno == EAGAIN) {
- /* Block until child has some I/O ready. */
- __archive_check_child(state->child_stdin,
- state->child_stdout);
- } else {
- /* Write failed. */
- close(state->child_stdin);
- state->child_stdin = -1;
- fcntl(state->child_stdout, F_SETFL, 0);
- /* If it was a bad error, we're done; otherwise
- * it was EPIPE or EOF, and we can still read
- * from the child. */
- if (ret == -1 && errno != EPIPE)
- return (-1);
- }
- }
-}
-
-int
-__archive_read_program(struct archive_read_filter *self, const char *cmd)
-{
- struct program_filter *state;
- static const size_t out_buf_len = 65536;
- char *out_buf;
- char *description;
- const char *prefix = "Program: ";
-
- state = (struct program_filter *)calloc(1, sizeof(*state));
- out_buf = (char *)malloc(out_buf_len);
- description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
- if (state == NULL || out_buf == NULL || description == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate input data");
- free(state);
- free(out_buf);
- free(description);
- return (ARCHIVE_FATAL);
- }
-
- self->code = ARCHIVE_COMPRESSION_PROGRAM;
- state->description = description;
- strcpy(state->description, prefix);
- strcat(state->description, cmd);
- self->name = state->description;
-
- state->out_buf = out_buf;
- state->out_buf_len = out_buf_len;
-
- if ((state->child = __archive_create_child(cmd,
- &state->child_stdin, &state->child_stdout)) == -1) {
- free(state->out_buf);
- free(state);
- archive_set_error(&self->archive->archive, EINVAL,
- "Can't initialise filter");
- return (ARCHIVE_FATAL);
- }
-
- self->data = state;
- self->read = program_filter_read;
- self->skip = NULL;
- self->close = program_filter_close;
-
- /* XXX Check that we can read at least one byte? */
- return (ARCHIVE_OK);
-}
-
-static int
-program_bidder_init(struct archive_read_filter *self)
-{
- struct program_bidder *bidder_state;
-
- bidder_state = (struct program_bidder *)self->bidder->data;
- return (__archive_read_program(self, bidder_state->cmd));
-}
-
-static ssize_t
-program_filter_read(struct archive_read_filter *self, const void **buff)
-{
- struct program_filter *state;
- ssize_t bytes;
- size_t total;
- char *p;
-
- state = (struct program_filter *)self->data;
-
- total = 0;
- p = state->out_buf;
- while (state->child_stdout != -1 && total < state->out_buf_len) {
- bytes = child_read(self, p, state->out_buf_len - total);
- if (bytes < 0)
- /* No recovery is possible if we can no longer
- * read from the child. */
- return (ARCHIVE_FATAL);
- if (bytes == 0)
- /* We got EOF from the child. */
- break;
- total += bytes;
- p += bytes;
- }
-
- *buff = state->out_buf;
- return (total);
-}
-
-static int
-program_filter_close(struct archive_read_filter *self)
-{
- struct program_filter *state;
- int e;
-
- state = (struct program_filter *)self->data;
- e = child_stop(self, state);
-
- /* Release our private data. */
- free(state->out_buf);
- free(state->description);
- free(state);
-
- return (e);
-}
-
-#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_compression_rpm.c
--- a/head/contrib/libarchive/libarchive/archive_read_support_compression_rpm.c Fri Mar 02 16:58:39 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,287 +0,0 @@
-/*-
- * Copyright (c) 2009 Michihiro NAKAJIMA
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_endian.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-struct rpm {
- int64_t total_in;
- size_t hpos;
- size_t hlen;
- unsigned char header[16];
- enum {
- ST_LEAD, /* Skipping 'Lead' section. */
- ST_HEADER, /* Reading 'Header' section;
- * first 16 bytes. */
- ST_HEADER_DATA, /* Skipping 'Header' section. */
- ST_PADDING, /* Skipping padding data after the
- * 'Header' section. */
- ST_ARCHIVE /* Reading 'Archive' section. */
- } state;
- int first_header;
-};
-#define RPM_LEAD_SIZE 96 /* Size of 'Lead' section. */
-
-static int rpm_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *);
-static int rpm_bidder_init(struct archive_read_filter *);
-
-static ssize_t rpm_filter_read(struct archive_read_filter *,
- const void **);
-static int rpm_filter_close(struct archive_read_filter *);
-
-int
-archive_read_support_compression_rpm(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *bidder;
-
- bidder = __archive_read_get_bidder(a);
- archive_clear_error(_a);
- if (bidder == NULL)
- return (ARCHIVE_FATAL);
-
- bidder->data = NULL;
- bidder->bid = rpm_bidder_bid;
- bidder->init = rpm_bidder_init;
- bidder->options = NULL;
- bidder->free = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
-rpm_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- const unsigned char *b;
- ssize_t avail;
- int bits_checked;
-
- (void)self; /* UNUSED */
-
- b = __archive_read_filter_ahead(filter, 8, &avail);
- if (b == NULL)
- return (0);
-
- bits_checked = 0;
- /*
- * Verify Header Magic Bytes : 0xed 0xab 0xee 0xdb
- */
- if (b[0] != 0xed)
- return (0);
- bits_checked += 8;
- if (b[1] != 0xab)
- return (0);
- bits_checked += 8;
- if (b[2] != 0xee)
- return (0);
- bits_checked += 8;
- if (b[3] != 0xdb)
- return (0);
- bits_checked += 8;
- /*
- * Check major version.
- */
- if (b[4] != 3 && b[4] != 4)
- return (0);
- bits_checked += 8;
- /*
- * Check package type; binary or source.
- */
- if (b[6] != 0)
- return (0);
- bits_checked += 8;
- if (b[7] != 0 && b[7] != 1)
- return (0);
- bits_checked += 8;
-
- return (bits_checked);
-}
-
-static int
-rpm_bidder_init(struct archive_read_filter *self)
-{
- struct rpm *rpm;
-
- self->code = ARCHIVE_COMPRESSION_RPM;
- self->name = "rpm";
- self->read = rpm_filter_read;
- self->skip = NULL; /* not supported */
- self->close = rpm_filter_close;
-
- rpm = (struct rpm *)calloc(sizeof(*rpm), 1);
- if (rpm == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for rpm");
- return (ARCHIVE_FATAL);
- }
-
- self->data = rpm;
- rpm->state = ST_LEAD;
-
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-rpm_filter_read(struct archive_read_filter *self, const void **buff)
-{
- struct rpm *rpm;
- const unsigned char *b;
- ssize_t avail_in, total;
- size_t used, n;
- uint32_t section;
- uint32_t bytes;
-
- rpm = (struct rpm *)self->data;
- *buff = NULL;
- total = avail_in = 0;
- b = NULL;
- used = 0;
- do {
- if (b == NULL) {
- b = __archive_read_filter_ahead(self->upstream, 1,
- &avail_in);
- if (b == NULL) {
- if (avail_in < 0)
- return (ARCHIVE_FATAL);
- else
- break;
- }
- }
-
- switch (rpm->state) {
- case ST_LEAD:
- if (rpm->total_in + avail_in < RPM_LEAD_SIZE)
- used += avail_in;
- else {
- n = RPM_LEAD_SIZE - rpm->total_in;
- used += n;
- b += n;
- rpm->state = ST_HEADER;
- rpm->hpos = 0;
- rpm->hlen = 0;
- rpm->first_header = 1;
- }
- break;
- case ST_HEADER:
- n = 16 - rpm->hpos;
- if (n > avail_in - used)
- n = avail_in - used;
- memcpy(rpm->header+rpm->hpos, b, n);
- b += n;
- used += n;
- rpm->hpos += n;
-
- if (rpm->hpos == 16) {
- if (rpm->header[0] != 0x8e ||
- rpm->header[1] != 0xad ||
- rpm->header[2] != 0xe8 ||
- rpm->header[3] != 0x01) {
- if (rpm->first_header) {
- archive_set_error(
- &self->archive->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Unrecoginized rpm header");
- return (ARCHIVE_FATAL);
- }
- rpm->state = ST_ARCHIVE;
- *buff = rpm->header;
- total = rpm->hpos;
- break;
- }
- /* Calculate 'Header' length. */
- section = archive_be32dec(rpm->header+8);
- bytes = archive_be32dec(rpm->header+12);
- rpm->hlen = 16 + section * 16 + bytes;
- rpm->state = ST_HEADER_DATA;
- rpm->first_header = 0;
- }
- break;
- case ST_HEADER_DATA:
- n = rpm->hlen - rpm->hpos;
- if (n > avail_in - used)
- n = avail_in - used;
- b += n;
- used += n;
- rpm->hpos += n;
- if (rpm->hpos == rpm->hlen)
- rpm->state = ST_PADDING;
- break;
- case ST_PADDING:
- while (used < (size_t)avail_in) {
- if (*b != 0) {
- /* Read next header. */
- rpm->state = ST_HEADER;
- rpm->hpos = 0;
- rpm->hlen = 0;
- break;
- }
- b++;
- used++;
- }
- break;
- case ST_ARCHIVE:
- *buff = b;
- total = avail_in;
- used = avail_in;
- break;
- }
- if (used == (size_t)avail_in) {
- rpm->total_in += used;
- __archive_read_filter_consume(self->upstream, used);
- b = NULL;
- used = 0;
- }
- } while (total == 0 && avail_in > 0);
-
- if (used > 0 && b != NULL) {
- rpm->total_in += used;
- __archive_read_filter_consume(self->upstream, used);
- }
- return (total);
-}
-
-static int
-rpm_filter_close(struct archive_read_filter *self)
-{
- struct rpm *rpm;
-
- rpm = (struct rpm *)self->data;
- free(rpm);
-
- return (ARCHIVE_OK);
-}
-
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_compression_uu.c
--- a/head/contrib/libarchive/libarchive/archive_read_support_compression_uu.c Fri Mar 02 16:58:39 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,637 +0,0 @@
-/*-
- * Copyright (c) 2009 Michihiro NAKAJIMA
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/contrib/libarchive/libarchive/archive_read_support_compression_uu.c 228763 2011-12-21 11:13:29Z mm $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-struct uudecode {
- int64_t total;
- unsigned char *in_buff;
-#define IN_BUFF_SIZE (1024)
- int in_cnt;
- size_t in_allocated;
- unsigned char *out_buff;
-#define OUT_BUFF_SIZE (64 * 1024)
- int state;
-#define ST_FIND_HEAD 0
-#define ST_READ_UU 1
-#define ST_UUEND 2
-#define ST_READ_BASE64 3
-};
-
-static int uudecode_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *filter);
-static int uudecode_bidder_init(struct archive_read_filter *);
-
-static ssize_t uudecode_filter_read(struct archive_read_filter *,
- const void **);
-static int uudecode_filter_close(struct archive_read_filter *);
-
-int
-archive_read_support_compression_uu(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *bidder;
-
- bidder = __archive_read_get_bidder(a);
- archive_clear_error(_a);
- if (bidder == NULL)
- return (ARCHIVE_FATAL);
-
- bidder->data = NULL;
- bidder->bid = uudecode_bidder_bid;
- bidder->init = uudecode_bidder_init;
- bidder->options = NULL;
- bidder->free = NULL;
- return (ARCHIVE_OK);
-}
-
-static const unsigned char ascii[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', 0, 0, '\r', 0, 0, /* 00 - 0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
-};
-
-static const unsigned char uuchar[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
-};
-
-static const unsigned char base64[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, /* 20 - 2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 30 - 3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 50 - 5F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 - 7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
-};
-
-static const int base64num[128] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 62, 0, 0, 0, 63, /* 20 - 2F */
- 52, 53, 54, 55, 56, 57, 58, 59,
- 60, 61, 0, 0, 0, 0, 0, 0, /* 30 - 3F */
- 0, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, /* 40 - 4F */
- 15, 16, 17, 18, 19, 20, 21, 22,
- 23, 24, 25, 0, 0, 0, 0, 0, /* 50 - 5F */
- 0, 26, 27, 28, 29, 30, 31, 32,
- 33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */
- 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 0, 0, 0, 0, 0, /* 70 - 7F */
-};
-
-static ssize_t
-get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize)
-{
- ssize_t len;
-
- len = 0;
- while (len < avail) {
- switch (ascii[*b]) {
- case 0: /* Non-ascii character or control character. */
- if (nlsize != NULL)
- *nlsize = 0;
- return (-1);
- case '\r':
- if (avail-len > 1 && b[1] == '\n') {
- if (nlsize != NULL)
- *nlsize = 2;
- return (len+2);
- }
- /* FALL THROUGH */
- case '\n':
- if (nlsize != NULL)
- *nlsize = 1;
- return (len+1);
- case 1:
- b++;
- len++;
- break;
- }
- }
- if (nlsize != NULL)
- *nlsize = 0;
- return (avail);
-}
-
-static ssize_t
-bid_get_line(struct archive_read_filter *filter,
- const unsigned char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl)
-{
- ssize_t len;
- int quit;
-
- quit = 0;
- if (*avail == 0) {
- *nl = 0;
- len = 0;
- } else
- len = get_line(*b, *avail, nl);
- /*
- * Read bytes more while it does not reach the end of line.
- */
- while (*nl == 0 && len == *avail && !quit) {
- ssize_t diff = *ravail - *avail;
-
- *b = __archive_read_filter_ahead(filter, 160 + *ravail, avail);
- if (*b == NULL) {
- if (*ravail >= *avail)
- return (0);
- /* Reading bytes reaches the end of file. */
- *b = __archive_read_filter_ahead(filter, *avail, avail);
- quit = 1;
- }
- *ravail = *avail;
- *b += diff;
- *avail -= diff;
- len = get_line(*b, *avail, nl);
- }
- return (len);
-}
-
-#define UUDECODE(c) (((c) - 0x20) & 0x3f)
-
-static int
-uudecode_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- const unsigned char *b;
- ssize_t avail, ravail;
- ssize_t len, nl;
- int l;
- int firstline;
-
- (void)self; /* UNUSED */
-
- b = __archive_read_filter_ahead(filter, 1, &avail);
- if (b == NULL)
- return (0);
-
- firstline = 20;
- ravail = avail;
- for (;;) {
- len = bid_get_line(filter, &b, &avail, &ravail, &nl);
- if (len < 0 || nl == 0)
- return (0);/* Binary data. */
- if (memcmp(b, "begin ", 6) == 0 && len - nl >= 11)
- l = 6;
- else if (memcmp(b, "begin-base64 ", 13) == 0 && len - nl >= 18)
- l = 13;
- else
- l = 0;
-
- if (l > 0 && (b[l] < '0' || b[l] > '7' ||
- b[l+1] < '0' || b[l+1] > '7' ||
- b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' '))
- l = 0;
-
- b += len;
- avail -= len;
- if (l)
- break;
- firstline = 0;
- }
- if (!avail)
- return (0);
- len = bid_get_line(filter, &b, &avail, &ravail, &nl);
- if (len < 0 || nl == 0)
- return (0);/* There are non-ascii characters. */
- avail -= len;
-
- if (l == 6) {
- if (!uuchar[*b])
- return (0);
- /* Get a length of decoded bytes. */
- l = UUDECODE(*b++); len--;
- if (l > 45)
- /* Normally, maximum length is 45(character 'M'). */
- return (0);
- while (l && len-nl > 0) {
- if (l > 0) {
- if (!uuchar[*b++])
- return (0);
- if (!uuchar[*b++])
- return (0);
- len -= 2;
- --l;
- }
- if (l > 0) {
- if (!uuchar[*b++])
- return (0);
- --len;
- --l;
- }
- if (l > 0) {
- if (!uuchar[*b++])
- return (0);
- --len;
- --l;
- }
- }
- if (len-nl < 0)
- return (0);
- if (len-nl == 1 &&
- (uuchar[*b] || /* Check sum. */
- (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */
- ++b;
- --len;
- }
- b += nl;
- if (avail && uuchar[*b])
- return (firstline+30);
- }
- if (l == 13) {
- while (len-nl > 0) {
- if (!base64[*b++])
- return (0);
- --len;
- }
- b += nl;
-
- if (avail >= 5 && memcmp(b, "====\n", 5) == 0)
- return (firstline+40);
- if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)
- return (firstline+40);
- if (avail > 0 && base64[*b])
- return (firstline+30);
- }
-
- return (0);
-}
-
-static int
-uudecode_bidder_init(struct archive_read_filter *self)
-{
- struct uudecode *uudecode;
- void *out_buff;
- void *in_buff;
-
- self->code = ARCHIVE_COMPRESSION_UU;
- self->name = "uu";
- self->read = uudecode_filter_read;
- self->skip = NULL; /* not supported */
- self->close = uudecode_filter_close;
-
- uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1);
- out_buff = malloc(OUT_BUFF_SIZE);
- in_buff = malloc(IN_BUFF_SIZE);
- if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for uudecode");
- free(uudecode);
- free(out_buff);
- free(in_buff);
- return (ARCHIVE_FATAL);
- }
-
- self->data = uudecode;
- uudecode->in_buff = in_buff;
- uudecode->in_cnt = 0;
- uudecode->in_allocated = IN_BUFF_SIZE;
- uudecode->out_buff = out_buff;
- uudecode->state = ST_FIND_HEAD;
-
- return (ARCHIVE_OK);
-}
-
-static int
-ensure_in_buff_size(struct archive_read_filter *self,
- struct uudecode *uudecode, size_t size)
-{
-
- if (size > uudecode->in_allocated) {
- unsigned char *ptr;
- size_t newsize;
-
- /*
- * Calculate a new buffer size for in_buff.
- * Increase its value until it has enough size we need.
- */
- newsize = uudecode->in_allocated;
- do {
- if (newsize < IN_BUFF_SIZE*32)
- newsize <<= 1;
- else
- newsize += IN_BUFF_SIZE;
- } while (size > newsize);
- ptr = malloc(newsize);
- if (ptr == NULL ||
- newsize < uudecode->in_allocated) {
- free(ptr);
- archive_set_error(&self->archive->archive,
- ENOMEM,
- "Can't allocate data for uudecode");
- return (ARCHIVE_FATAL);
- }
- if (uudecode->in_cnt)
- memmove(ptr, uudecode->in_buff,
- uudecode->in_cnt);
- free(uudecode->in_buff);
- uudecode->in_buff = ptr;
- uudecode->in_allocated = newsize;
- }
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-uudecode_filter_read(struct archive_read_filter *self, const void **buff)
-{
- struct uudecode *uudecode;
- const unsigned char *b, *d;
- unsigned char *out;
- ssize_t avail_in, ravail;
- ssize_t used;
- ssize_t total;
- ssize_t len, llen, nl;
-
- uudecode = (struct uudecode *)self->data;
-
-read_more:
- d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);
- if (d == NULL && avail_in < 0)
- return (ARCHIVE_FATAL);
- /* Quiet a code analyzer; make sure avail_in must be zero
- * when d is NULL. */
- if (d == NULL)
- avail_in = 0;
- used = 0;
- total = 0;
- out = uudecode->out_buff;
- ravail = avail_in;
- if (uudecode->in_cnt) {
- /*
- * If there is remaining data which is saved by
- * previous calling, use it first.
- */
- if (ensure_in_buff_size(self, uudecode,
- avail_in + uudecode->in_cnt) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- memcpy(uudecode->in_buff + uudecode->in_cnt,
- d, avail_in);
- d = uudecode->in_buff;
- avail_in += uudecode->in_cnt;
- uudecode->in_cnt = 0;
- }
- for (;used < avail_in; d += llen, used += llen) {
- int l, body;
-
- b = d;
- len = get_line(b, avail_in - used, &nl);
- if (len < 0) {
- /* Non-ascii character is found. */
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- llen = len;
- if (nl == 0) {
- /*
- * Save remaining data which does not contain
- * NL('\n','\r').
- */
- if (ensure_in_buff_size(self, uudecode, len)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- if (uudecode->in_buff != b)
- memmove(uudecode->in_buff, b, len);
- uudecode->in_cnt = len;
- if (total == 0) {
- /* Do not return 0; it means end-of-file.
- * We should try to read bytes more. */
- __archive_read_filter_consume(
- self->upstream, ravail);
- goto read_more;
- }
- break;
- }
- if (total + len * 2 > OUT_BUFF_SIZE)
- break;
- switch (uudecode->state) {
- default:
- case ST_FIND_HEAD:
- if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
- l = 6;
- else if (len - nl >= 18 &&
- memcmp(b, "begin-base64 ", 13) == 0)
- l = 13;
- else
- l = 0;
- if (l != 0 && b[l] >= '0' && b[l] <= '7' &&
- b[l+1] >= '0' && b[l+1] <= '7' &&
- b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') {
- if (l == 6)
- uudecode->state = ST_READ_UU;
- else
- uudecode->state = ST_READ_BASE64;
- }
- break;
- case ST_READ_UU:
- body = len - nl;
- if (!uuchar[*b] || body <= 0) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- /* Get length of undecoded bytes of curent line. */
- l = UUDECODE(*b++);
- body--;
- if (l > body) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- if (l == 0) {
- uudecode->state = ST_UUEND;
- break;
- }
- while (l > 0) {
- int n = 0;
-
- if (l > 0) {
- if (!uuchar[b[0]] || !uuchar[b[1]])
- break;
- n = UUDECODE(*b++) << 18;
- n |= UUDECODE(*b++) << 12;
- *out++ = n >> 16; total++;
- --l;
- }
- if (l > 0) {
- if (!uuchar[b[0]])
- break;
- n |= UUDECODE(*b++) << 6;
- *out++ = (n >> 8) & 0xFF; total++;
- --l;
- }
- if (l > 0) {
- if (!uuchar[b[0]])
- break;
- n |= UUDECODE(*b++);
- *out++ = n & 0xFF; total++;
- --l;
- }
- }
- if (l) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- break;
- case ST_UUEND:
- if (len - nl == 3 && memcmp(b, "end ", 3) == 0)
- uudecode->state = ST_FIND_HEAD;
- else {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- break;
- case ST_READ_BASE64:
- l = len - nl;
- if (l >= 3 && b[0] == '=' && b[1] == '=' &&
- b[2] == '=') {
- uudecode->state = ST_FIND_HEAD;
- break;
- }
- while (l > 0) {
- int n = 0;
-
- if (l > 0) {
- if (!base64[b[0]] || !base64[b[1]])
- break;
- n = base64num[*b++] << 18;
- n |= base64num[*b++] << 12;
- *out++ = n >> 16; total++;
- l -= 2;
- }
- if (l > 0) {
- if (*b == '=')
- break;
- if (!base64[*b])
- break;
- n |= base64num[*b++] << 6;
- *out++ = (n >> 8) & 0xFF; total++;
- --l;
- }
- if (l > 0) {
- if (*b == '=')
- break;
- if (!base64[*b])
- break;
- n |= base64num[*b++];
- *out++ = n & 0xFF; total++;
- --l;
- }
- }
- if (l && *b != '=') {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- break;
- }
- }
-
- __archive_read_filter_consume(self->upstream, ravail);
-
- *buff = uudecode->out_buff;
- uudecode->total += total;
- return (total);
-}
-
-static int
-uudecode_filter_close(struct archive_read_filter *self)
-{
- struct uudecode *uudecode;
-
- uudecode = (struct uudecode *)self->data;
- free(uudecode->in_buff);
- free(uudecode->out_buff);
- free(uudecode);
-
- return (ARCHIVE_OK);
-}
-
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_compression_xz.c
--- a/head/contrib/libarchive/libarchive/archive_read_support_compression_xz.c Fri Mar 02 16:58:39 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,708 +0,0 @@
-/*-
- * Copyright (c) 2009 Michihiro NAKAJIMA
- * Copyright (c) 2003-2008 Tim Kientzle and Miklos Vajna
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-
-__FBSDID("$FreeBSD: head/contrib/libarchive/libarchive/archive_read_support_compression_xz.c 228763 2011-12-21 11:13:29Z mm $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if HAVE_LZMA_H
-#include <lzma.h>
-#elif HAVE_LZMADEC_H
-#include <lzmadec.h>
-#endif
-
-#include "archive.h"
-#include "archive_endian.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-#if HAVE_LZMA_H && HAVE_LIBLZMA
-
-struct private_data {
- lzma_stream stream;
- unsigned char *out_block;
- size_t out_block_size;
- int64_t total_out;
- char eof; /* True = found end of compressed data. */
-};
-
-/* Combined lzma/xz filter */
-static ssize_t xz_filter_read(struct archive_read_filter *, const void **);
-static int xz_filter_close(struct archive_read_filter *);
-static int xz_lzma_bidder_init(struct archive_read_filter *);
-
-#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
-
-struct private_data {
- lzmadec_stream stream;
- unsigned char *out_block;
- size_t out_block_size;
- int64_t total_out;
- char eof; /* True = found end of compressed data. */
-};
-
-/* Lzma-only filter */
-static ssize_t lzma_filter_read(struct archive_read_filter *, const void **);
-static int lzma_filter_close(struct archive_read_filter *);
-#endif
-
-/*
- * Note that we can detect xz and lzma compressed files even if we
- * can't decompress them. (In fact, we like detecting them because we
- * can give better error messages.) So the bid framework here gets
- * compiled even if no lzma library is available.
- */
-static int xz_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *);
-static int xz_bidder_init(struct archive_read_filter *);
-static int lzma_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *);
-static int lzma_bidder_init(struct archive_read_filter *);
-
-int
-archive_read_support_compression_xz(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *bidder = __archive_read_get_bidder(a);
-
- archive_clear_error(_a);
- if (bidder == NULL)
- return (ARCHIVE_FATAL);
-
- bidder->data = NULL;
- bidder->bid = xz_bidder_bid;
- bidder->init = xz_bidder_init;
- bidder->options = NULL;
- bidder->free = NULL;
-#if HAVE_LZMA_H && HAVE_LIBLZMA
- return (ARCHIVE_OK);
-#else
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "Using external unxz program for xz decompression");
- return (ARCHIVE_WARN);
-#endif
-}
-
-int
-archive_read_support_compression_lzma(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *bidder = __archive_read_get_bidder(a);
-
- archive_clear_error(_a);
- if (bidder == NULL)
- return (ARCHIVE_FATAL);
-
- bidder->data = NULL;
- bidder->bid = lzma_bidder_bid;
- bidder->init = lzma_bidder_init;
- bidder->options = NULL;
- bidder->free = NULL;
-#if HAVE_LZMA_H && HAVE_LIBLZMA
- return (ARCHIVE_OK);
-#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
- return (ARCHIVE_OK);
-#else
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "Using external unlzma program for lzma decompression");
- return (ARCHIVE_WARN);
-#endif
-}
-
-/*
- * Test whether we can handle this data.
- */
-static int
-xz_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- const unsigned char *buffer;
- ssize_t avail;
- int bits_checked;
-
- (void)self; /* UNUSED */
-
- buffer = __archive_read_filter_ahead(filter, 6, &avail);
- if (buffer == NULL)
- return (0);
-
- /*
- * Verify Header Magic Bytes : FD 37 7A 58 5A 00
- */
- bits_checked = 0;
- if (buffer[0] != 0xFD)
- return (0);
- bits_checked += 8;
- if (buffer[1] != 0x37)
- return (0);
- bits_checked += 8;
- if (buffer[2] != 0x7A)
- return (0);
- bits_checked += 8;
- if (buffer[3] != 0x58)
- return (0);
- bits_checked += 8;
- if (buffer[4] != 0x5A)
- return (0);
- bits_checked += 8;
- if (buffer[5] != 0x00)
- return (0);
- bits_checked += 8;
-
- return (bits_checked);
-}
-
-/*
- * Test whether we can handle this data.
- *
- * <sigh> LZMA has a rather poor file signature. Zeros do not
- * make good signature bytes as a rule, and the only non-zero byte
- * here is an ASCII character. For example, an uncompressed tar
- * archive whose first file is ']' would satisfy this check. It may
- * be necessary to exclude LZMA from compression_all() because of
- * this. Clients of libarchive would then have to explicitly enable
- * LZMA checking instead of (or in addition to) compression_all() when
- * they have other evidence (file name, command-line option) to go on.
- */
-static int
-lzma_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- const unsigned char *buffer;
- ssize_t avail;
- uint32_t dicsize;
- uint64_t uncompressed_size;
- int bits_checked;
-
- (void)self; /* UNUSED */
-
- buffer = __archive_read_filter_ahead(filter, 14, &avail);
- if (buffer == NULL)
- return (0);
-
- /* First byte of raw LZMA stream is commonly 0x5d.
- * The first byte is a special number, which consists of
- * three parameters of LZMA compression, a number of literal
- * context bits(which is from 0 to 8, default is 3), a number
- * of literal pos bits(which is from 0 to 4, default is 0),
- * a number of pos bits(which is from 0 to 4, default is 2).
- * The first byte is made by
- * (pos bits * 5 + literal pos bit) * 9 + * literal contest bit,
- * and so the default value in this field is
- * (2 * 5 + 0) * 9 + 3 = 0x5d.
- * lzma of LZMA SDK has options to change those parameters.
- * It means a range of this field is from 0 to 224. And lzma of
- * XZ Utils with option -e records 0x5e in this field. */
- /* NOTE: If this checking of the first byte increases false
- * recognition, we should allow only 0x5d and 0x5e for the first
- * byte of LZMA stream. */
- bits_checked = 0;
- if (buffer[0] > (4 * 5 + 4) * 9 + 8)
- return (0);
- /* Most likely value in the first byte of LZMA stream. */
- if (buffer[0] == 0x5d || buffer[0] == 0x5e)
- bits_checked += 8;
-
- /* Sixth through fourteenth bytes are uncompressed size,
- * stored in little-endian order. `-1' means uncompressed
- * size is unknown and lzma of XZ Utils always records `-1'
- * in this field. */
- uncompressed_size = archive_le64dec(buffer+5);
- if (uncompressed_size == (uint64_t)ARCHIVE_LITERAL_LL(-1))
- bits_checked += 64;
-
- /* Second through fifth bytes are dictionary size, stored in
- * little-endian order. The minimum dictionary size is
- * 1 << 12(4KiB) which the lzma of LZMA SDK uses with option
- * -d12 and the maxinam dictionary size is 1 << 27(128MiB)
- * which the one uses with option -d27.
- * NOTE: A comment of LZMA SDK source code says this dictionary
- * range is from 1 << 12 to 1 << 30. */
- dicsize = archive_le32dec(buffer+1);
- switch (dicsize) {
- case 0x00001000:/* lzma of LZMA SDK option -d12. */
- case 0x00002000:/* lzma of LZMA SDK option -d13. */
- case 0x00004000:/* lzma of LZMA SDK option -d14. */
- case 0x00008000:/* lzma of LZMA SDK option -d15. */
- case 0x00010000:/* lzma of XZ Utils option -0 and -1.
- * lzma of LZMA SDK option -d16. */
- case 0x00020000:/* lzma of LZMA SDK option -d17. */
- case 0x00040000:/* lzma of LZMA SDK option -d18. */
- case 0x00080000:/* lzma of XZ Utils option -2.
- * lzma of LZMA SDK option -d19. */
- case 0x00100000:/* lzma of XZ Utils option -3.
- * lzma of LZMA SDK option -d20. */
- case 0x00200000:/* lzma of XZ Utils option -4.
- * lzma of LZMA SDK option -d21. */
- case 0x00400000:/* lzma of XZ Utils option -5.
- * lzma of LZMA SDK option -d22. */
- case 0x00800000:/* lzma of XZ Utils option -6.
- * lzma of LZMA SDK option -d23. */
- case 0x01000000:/* lzma of XZ Utils option -7.
- * lzma of LZMA SDK option -d24. */
- case 0x02000000:/* lzma of XZ Utils option -8.
- * lzma of LZMA SDK option -d25. */
- case 0x04000000:/* lzma of XZ Utils option -9.
- * lzma of LZMA SDK option -d26. */
- case 0x08000000:/* lzma of LZMA SDK option -d27. */
- bits_checked += 32;
- break;
- default:
- /* If a memory usage for encoding was not enough on
- * the platform where LZMA stream was made, lzma of
- * XZ Utils automatically decreased the dictionary
- * size to enough memory for encoding by 1Mi bytes
- * (1 << 20).*/
- if (dicsize <= 0x03F00000 && dicsize >= 0x00300000 &&
- (dicsize & ((1 << 20)-1)) == 0 &&
- bits_checked == 8 + 64) {
- bits_checked += 32;
- break;
- }
- /* Otherwise dictionary size is unlikely. But it is
- * possible that someone makes lzma stream with
- * liblzma/LZMA SDK in one's dictionary size. */
- return (0);
- }
-
- /* TODO: The above test is still very weak. It would be
- * good to do better. */
-
- return (bits_checked);
-}
-
-#if HAVE_LZMA_H && HAVE_LIBLZMA
-
-/*
- * liblzma 4.999.7 and later support both lzma and xz streams.
- */
-static int
-xz_bidder_init(struct archive_read_filter *self)
-{
- self->code = ARCHIVE_COMPRESSION_XZ;
- self->name = "xz";
- return (xz_lzma_bidder_init(self));
-}
-
-static int
-lzma_bidder_init(struct archive_read_filter *self)
-{
- self->code = ARCHIVE_COMPRESSION_LZMA;
- self->name = "lzma";
- return (xz_lzma_bidder_init(self));
-}
-
-/*
- * Setup the callbacks.
- */
-static int
-xz_lzma_bidder_init(struct archive_read_filter *self)
-{
- static const size_t out_block_size = 64 * 1024;
- void *out_block;
- struct private_data *state;
- int ret;
-
- state = (struct private_data *)calloc(sizeof(*state), 1);
- out_block = (unsigned char *)malloc(out_block_size);
- if (state == NULL || out_block == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for xz decompression");
- free(out_block);
- free(state);
- return (ARCHIVE_FATAL);
- }
-
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->read = xz_filter_read;
- self->skip = NULL; /* not supported */
- self->close = xz_filter_close;
-
- state->stream.avail_in = 0;
-
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
-
- /* Initialize compression library.
- * TODO: I don't know what value is best for memlimit.
- * maybe, it needs to check memory size which
- * running system has.
- */
- if (self->code == ARCHIVE_COMPRESSION_XZ)
- ret = lzma_stream_decoder(&(state->stream),
- (1U << 30),/* memlimit */
- LZMA_CONCATENATED);
- else
- ret = lzma_alone_decoder(&(state->stream),
- (1U << 30));/* memlimit */
-
- if (ret == LZMA_OK)
- return (ARCHIVE_OK);
-
- /* Library setup failed: Choose an error message and clean up. */
- switch (ret) {
- case LZMA_MEM_ERROR:
- archive_set_error(&self->archive->archive, ENOMEM,
- "Internal error initializing compression library: "
- "Cannot allocate memory");
- break;
- case LZMA_OPTIONS_ERROR:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "Invalid or unsupported options");
- break;
- default:
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing lzma library");
- break;
- }
-
- free(state->out_block);
- free(state);
- self->data = NULL;
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Return the next block of decompressed data.
- */
-static ssize_t
-xz_filter_read(struct archive_read_filter *self, const void **p)
-{
- struct private_data *state;
- size_t decompressed;
- ssize_t avail_in;
- int ret;
-
- state = (struct private_data *)self->data;
-
- /* Empty our output buffer. */
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
-
- /* Try to fill the output buffer. */
- while (state->stream.avail_out > 0 && !state->eof) {
- state->stream.next_in =
- __archive_read_filter_ahead(self->upstream, 1, &avail_in);
- if (state->stream.next_in == NULL && avail_in < 0)
- return (ARCHIVE_FATAL);
- state->stream.avail_in = avail_in;
-
- /* Decompress as much as we can in one pass. */
- ret = lzma_code(&(state->stream),
- (state->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN);
- switch (ret) {
- case LZMA_STREAM_END: /* Found end of stream. */
- state->eof = 1;
- /* FALL THROUGH */
- case LZMA_OK: /* Decompressor made some progress. */
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
- break;
- case LZMA_MEM_ERROR:
- archive_set_error(&self->archive->archive, ENOMEM,
- "Lzma library error: Cannot allocate memory");
- return (ARCHIVE_FATAL);
- case LZMA_MEMLIMIT_ERROR:
- archive_set_error(&self->archive->archive, ENOMEM,
- "Lzma library error: Out of memory");
- return (ARCHIVE_FATAL);
- case LZMA_FORMAT_ERROR:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma library error: format not recognized");
- return (ARCHIVE_FATAL);
- case LZMA_OPTIONS_ERROR:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma library error: Invalid options");
- return (ARCHIVE_FATAL);
- case LZMA_DATA_ERROR:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma library error: Corrupted input data");
- return (ARCHIVE_FATAL);
- case LZMA_BUF_ERROR:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma library error: No progress is possible");
- return (ARCHIVE_FATAL);
- default:
- /* Return an error. */
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma decompression failed: Unknown error");
- return (ARCHIVE_FATAL);
- }
- }
-
- decompressed = state->stream.next_out - state->out_block;
- state->total_out += decompressed;
- if (decompressed == 0)
- *p = NULL;
- else
- *p = state->out_block;
- return (decompressed);
-}
-
-/*
- * Clean up the decompressor.
- */
-static int
-xz_filter_close(struct archive_read_filter *self)
-{
- struct private_data *state;
-
- state = (struct private_data *)self->data;
- lzma_end(&(state->stream));
- free(state->out_block);
- free(state);
- return (ARCHIVE_OK);
-}
-
-#else
-
-#if HAVE_LZMADEC_H && HAVE_LIBLZMADEC
-
-/*
- * If we have the older liblzmadec library, then we can handle
- * LZMA streams but not XZ streams.
- */
-
-/*
- * Setup the callbacks.
- */
-static int
-lzma_bidder_init(struct archive_read_filter *self)
-{
- static const size_t out_block_size = 64 * 1024;
- void *out_block;
- struct private_data *state;
- ssize_t ret, avail_in;
-
- self->code = ARCHIVE_COMPRESSION_LZMA;
- self->name = "lzma";
-
- state = (struct private_data *)calloc(sizeof(*state), 1);
- out_block = (unsigned char *)malloc(out_block_size);
- if (state == NULL || out_block == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for lzma decompression");
- free(out_block);
- free(state);
- return (ARCHIVE_FATAL);
- }
-
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->read = lzma_filter_read;
- self->skip = NULL; /* not supported */
- self->close = lzma_filter_close;
-
- /* Prime the lzma library with 18 bytes of input. */
- state->stream.next_in = (unsigned char *)(uintptr_t)
- __archive_read_filter_ahead(self->upstream, 18, &avail_in);
- if (state->stream.next_in == NULL)
- return (ARCHIVE_FATAL);
- state->stream.avail_in = avail_in;
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
-
- /* Initialize compression library. */
- ret = lzmadec_init(&(state->stream));
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
- if (ret == LZMADEC_OK)
- return (ARCHIVE_OK);
-
- /* Library setup failed: Clean up. */
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing lzma library");
-
- /* Override the error message if we know what really went wrong. */
- switch (ret) {
- case LZMADEC_HEADER_ERROR:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "invalid header");
- break;
- case LZMADEC_MEM_ERROR:
- archive_set_error(&self->archive->archive, ENOMEM,
- "Internal error initializing compression library: "
- "out of memory");
- break;
- }
-
- free(state->out_block);
- free(state);
- self->data = NULL;
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Return the next block of decompressed data.
- */
-static ssize_t
-lzma_filter_read(struct archive_read_filter *self, const void **p)
-{
- struct private_data *state;
- size_t decompressed;
- ssize_t avail_in, ret;
-
- state = (struct private_data *)self->data;
-
- /* Empty our output buffer. */
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
-
- /* Try to fill the output buffer. */
- while (state->stream.avail_out > 0 && !state->eof) {
- state->stream.next_in = (unsigned char *)(uintptr_t)
- __archive_read_filter_ahead(self->upstream, 1, &avail_in);
- if (state->stream.next_in == NULL && avail_in < 0)
- return (ARCHIVE_FATAL);
- state->stream.avail_in = avail_in;
-
- /* Decompress as much as we can in one pass. */
- ret = lzmadec_decode(&(state->stream), avail_in == 0);
- switch (ret) {
- case LZMADEC_STREAM_END: /* Found end of stream. */
- state->eof = 1;
- /* FALL THROUGH */
- case LZMADEC_OK: /* Decompressor made some progress. */
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
- break;
- case LZMADEC_BUF_ERROR: /* Insufficient input data? */
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- default:
- /* Return an error. */
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma decompression failed");
- return (ARCHIVE_FATAL);
- }
- }
-
- decompressed = state->stream.next_out - state->out_block;
- state->total_out += decompressed;
- if (decompressed == 0)
- *p = NULL;
- else
- *p = state->out_block;
- return (decompressed);
-}
-
-/*
- * Clean up the decompressor.
- */
-static int
-lzma_filter_close(struct archive_read_filter *self)
-{
- struct private_data *state;
- int ret;
-
- state = (struct private_data *)self->data;
- ret = ARCHIVE_OK;
- switch (lzmadec_end(&(state->stream))) {
- case LZMADEC_OK:
- break;
- default:
- archive_set_error(&(self->archive->archive),
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up %s compressor",
- self->archive->archive.compression_name);
- ret = ARCHIVE_FATAL;
- }
-
- free(state->out_block);
- free(state);
- return (ret);
-}
-
-#else
-
-/*
- *
- * If we have no suitable library on this system, we can't actually do
- * the decompression. We can, however, still detect compressed
- * archives and emit a useful message.
- *
- */
-static int
-lzma_bidder_init(struct archive_read_filter *self)
-{
- int r;
-
- r = __archive_read_program(self, "unlzma");
- /* Note: We set the format here even if __archive_read_program()
- * above fails. We do, after all, know what the format is
- * even if we weren't able to read it. */
- self->code = ARCHIVE_COMPRESSION_LZMA;
- self->name = "lzma";
- return (r);
-}
-
-#endif /* HAVE_LZMADEC_H */
-
-
-static int
-xz_bidder_init(struct archive_read_filter *self)
-{
- int r;
-
- r = __archive_read_program(self, "unxz");
- /* Note: We set the format here even if __archive_read_program()
- * above fails. We do, after all, know what the format is
- * even if we weren't able to read it. */
- self->code = ARCHIVE_COMPRESSION_XZ;
- self->name = "xz";
- return (r);
-}
-
-
-#endif /* HAVE_LZMA_H */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_filter_all.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_filter_all.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2003-2011 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive.h"
+#include "archive_private.h"
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Deprecated; remove in libarchive 4.0 */
+int
+archive_read_support_compression_all(struct archive *a)
+{
+ return archive_read_support_filter_all(a);
+}
+#endif
+
+int
+archive_read_support_filter_all(struct archive *a)
+{
+ archive_check_magic(a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_all");
+
+ /* Bzip falls back to "bunzip2" command-line */
+ archive_read_support_filter_bzip2(a);
+ /* The decompress code doesn't use an outside library. */
+ archive_read_support_filter_compress(a);
+ /* Gzip decompress falls back to "gunzip" command-line. */
+ archive_read_support_filter_gzip(a);
+ /* Lzip falls back to "unlzip" command-line program. */
+ archive_read_support_filter_lzip(a);
+ /* The LZMA file format has a very weak signature, so it
+ * may not be feasible to keep this here, but we'll try.
+ * This will come back out if there are problems. */
+ /* Lzma falls back to "unlzma" command-line program. */
+ archive_read_support_filter_lzma(a);
+ /* Xz falls back to "unxz" command-line program. */
+ archive_read_support_filter_xz(a);
+ /* The decode code doesn't use an outside library. */
+ archive_read_support_filter_uu(a);
+ /* The decode code doesn't use an outside library. */
+ archive_read_support_filter_rpm(a);
+
+ /* Note: We always return ARCHIVE_OK here, even if some of the
+ * above return ARCHIVE_WARN. The intent here is to enable
+ * "as much as possible." Clients who need specific
+ * compression should enable those individually so they can
+ * verify the level of support. */
+ /* Clear any warning messages set by the above functions. */
+ archive_clear_error(a);
+ return (ARCHIVE_OK);
+}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,370 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_BZLIB_H
+#include <bzlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
+struct private_data {
+ bz_stream stream;
+ char *out_block;
+ size_t out_block_size;
+ char valid; /* True = decompressor is initialized */
+ char eof; /* True = found end of compressed data. */
+};
+
+/* Bzip2 filter */
+static ssize_t bzip2_filter_read(struct archive_read_filter *, const void **);
+static int bzip2_filter_close(struct archive_read_filter *);
+#endif
+
+/*
+ * Note that we can detect bzip2 archives even if we can't decompress
+ * them. (In fact, we like detecting them because we can give better
+ * error messages.) So the bid framework here gets compiled even
+ * if bzlib is unavailable.
+ */
+static int bzip2_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
+static int bzip2_reader_init(struct archive_read_filter *);
+static int bzip2_reader_free(struct archive_read_filter_bidder *);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Deprecated; remove in libarchive 4.0 */
+int
+archive_read_support_compression_bzip2(struct archive *a)
+{
+ return archive_read_support_filter_bzip2(a);
+}
+#endif
+
+int
+archive_read_support_filter_bzip2(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter_bidder *reader;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_bzip2");
+
+ if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ reader->data = NULL;
+ reader->bid = bzip2_reader_bid;
+ reader->init = bzip2_reader_init;
+ reader->options = NULL;
+ reader->free = bzip2_reader_free;
+#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
+ return (ARCHIVE_OK);
+#else
+ archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ "Using external bunzip2 program");
+ return (ARCHIVE_WARN);
+#endif
+}
+
+static int
+bzip2_reader_free(struct archive_read_filter_bidder *self){
+ (void)self; /* UNUSED */
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Test whether we can handle this data.
+ *
+ * This logic returns zero if any part of the signature fails. It
+ * also tries to Do The Right Thing if a very short buffer prevents us
+ * from verifying as much as we would like.
+ */
+static int
+bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_filter *filter)
+{
+ const unsigned char *buffer;
+ ssize_t avail;
+ int bits_checked;
+
+ (void)self; /* UNUSED */
+
+ /* Minimal bzip2 archive is 14 bytes. */
+ buffer = __archive_read_filter_ahead(filter, 14, &avail);
+ if (buffer == NULL)
+ return (0);
+
+ /* First three bytes must be "BZh" */
+ bits_checked = 0;
+ if (memcmp(buffer, "BZh", 3) != 0)
+ return (0);
+ bits_checked += 24;
+
+ /* Next follows a compression flag which must be an ASCII digit. */
+ if (buffer[3] < '1' || buffer[3] > '9')
+ return (0);
+ bits_checked += 5;
+
+ /* After BZh[1-9], there must be either a data block
+ * which begins with 0x314159265359 or an end-of-data
+ * marker of 0x177245385090. */
+ if (memcmp(buffer + 4, "\x31\x41\x59\x26\x53\x59", 6) == 0)
+ bits_checked += 48;
+ else if (memcmp(buffer + 4, "\x17\x72\x45\x38\x50\x90", 6) == 0)
+ bits_checked += 48;
+ else
+ return (0);
+
+ return (bits_checked);
+}
+
+#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
+
+/*
+ * If we don't have the library on this system, we can't actually do the
+ * decompression. We can, however, still detect compressed archives
+ * and emit a useful message.
+ */
+static int
+bzip2_reader_init(struct archive_read_filter *self)
+{
+ int r;
+
+ r = __archive_read_program(self, "bunzip2");
+ /* Note: We set the format here even if __archive_read_program()
+ * above fails. We do, after all, know what the format is
+ * even if we weren't able to read it. */
+ self->code = ARCHIVE_COMPRESSION_BZIP2;
+ self->name = "bzip2";
+ return (r);
+}
+
+
+#else
+
+/*
+ * Setup the callbacks.
+ */
+static int
+bzip2_reader_init(struct archive_read_filter *self)
+{
+ static const size_t out_block_size = 64 * 1024;
+ void *out_block;
+ struct private_data *state;
+
+ self->code = ARCHIVE_COMPRESSION_BZIP2;
+ self->name = "bzip2";
+
+ state = (struct private_data *)calloc(sizeof(*state), 1);
+ out_block = (unsigned char *)malloc(out_block_size);
+ if (state == NULL || out_block == NULL) {
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate data for bzip2 decompression");
+ free(out_block);
+ free(state);
+ return (ARCHIVE_FATAL);
+ }
+
+ self->data = state;
+ state->out_block_size = out_block_size;
+ state->out_block = out_block;
+ self->read = bzip2_filter_read;
+ self->skip = NULL; /* not supported */
+ self->close = bzip2_filter_close;
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Return the next block of decompressed data.
+ */
+static ssize_t
+bzip2_filter_read(struct archive_read_filter *self, const void **p)
+{
+ struct private_data *state;
+ size_t decompressed;
+ const char *read_buf;
+ ssize_t ret;
+
+ state = (struct private_data *)self->data;
+
+ if (state->eof) {
+ *p = NULL;
+ return (0);
+ }
+
+ /* Empty our output buffer. */
+ state->stream.next_out = state->out_block;
+ state->stream.avail_out = state->out_block_size;
+
+ /* Try to fill the output buffer. */
+ for (;;) {
+ if (!state->valid) {
+ if (bzip2_reader_bid(self->bidder, self->upstream) == 0) {
+ state->eof = 1;
+ *p = state->out_block;
+ decompressed = state->stream.next_out
+ - state->out_block;
+ return (decompressed);
+ }
+ /* Initialize compression library. */
+ ret = BZ2_bzDecompressInit(&(state->stream),
+ 0 /* library verbosity */,
+ 0 /* don't use low-mem algorithm */);
+
+ /* If init fails, try low-memory algorithm instead. */
+ if (ret == BZ_MEM_ERROR)
+ ret = BZ2_bzDecompressInit(&(state->stream),
+ 0 /* library verbosity */,
+ 1 /* do use low-mem algo */);
+
+ if (ret != BZ_OK) {
+ const char *detail = NULL;
+ int err = ARCHIVE_ERRNO_MISC;
+ switch (ret) {
+ case BZ_PARAM_ERROR:
+ detail = "invalid setup parameter";
+ break;
+ case BZ_MEM_ERROR:
+ err = ENOMEM;
+ detail = "out of memory";
+ break;
+ case BZ_CONFIG_ERROR:
+ detail = "mis-compiled library";
+ break;
+ }
+ archive_set_error(&self->archive->archive, err,
+ "Internal error initializing decompressor%s%s",
+ detail == NULL ? "" : ": ",
+ detail);
+ return (ARCHIVE_FATAL);
+ }
+ state->valid = 1;
+ }
+
+ /* stream.next_in is really const, but bzlib
+ * doesn't declare it so. <sigh> */
+ read_buf =
+ __archive_read_filter_ahead(self->upstream, 1, &ret);
+ if (read_buf == NULL) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "truncated bzip2 input");
+ return (ARCHIVE_FATAL);
+ }
+ state->stream.next_in = (char *)(uintptr_t)read_buf;
+ state->stream.avail_in = ret;
+ /* There is no more data, return whatever we have. */
+ if (ret == 0) {
+ state->eof = 1;
+ *p = state->out_block;
+ decompressed = state->stream.next_out
+ - state->out_block;
+ return (decompressed);
+ }
+
+ /* Decompress as much as we can in one pass. */
+ ret = BZ2_bzDecompress(&(state->stream));
+ __archive_read_filter_consume(self->upstream,
+ state->stream.next_in - read_buf);
+
+ switch (ret) {
+ case BZ_STREAM_END: /* Found end of stream. */
+ switch (BZ2_bzDecompressEnd(&(state->stream))) {
+ case BZ_OK:
+ break;
+ default:
+ archive_set_error(&(self->archive->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up decompressor");
+ return (ARCHIVE_FATAL);
+ }
+ state->valid = 0;
+ /* FALLTHROUGH */
+ case BZ_OK: /* Decompressor made some progress. */
+ /* If we filled our buffer, update stats and return. */
+ if (state->stream.avail_out == 0) {
+ *p = state->out_block;
+ decompressed = state->stream.next_out
+ - state->out_block;
+ return (decompressed);
+ }
+ break;
+ default: /* Return an error. */
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC, "bzip decompression failed");
+ return (ARCHIVE_FATAL);
+ }
+ }
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+bzip2_filter_close(struct archive_read_filter *self)
+{
+ struct private_data *state;
+ int ret = ARCHIVE_OK;
+
+ state = (struct private_data *)self->data;
+
+ if (state->valid) {
+ switch (BZ2_bzDecompressEnd(&state->stream)) {
+ case BZ_OK:
+ break;
+ default:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up decompressor");
+ ret = ARCHIVE_FATAL;
+ }
+ state->valid = 0;
+ }
+
+ free(state->out_block);
+ free(state);
+ return (ret);
+}
+
+#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_filter_compress.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_filter_compress.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,454 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code borrows heavily from "compress" source code, which is
+ * protected by the following copyright. (Clause 3 dropped by request
+ * of the Regents.)
+ */
+
+/*-
+ * Copyright (c) 1985, 1986, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis and James A. Woods, derived from original
+ * work by Spencer Thomas and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+/*
+ * Because LZW decompression is pretty simple, I've just implemented
+ * the whole decompressor here (cribbing from "compress" source code,
+ * of course), rather than relying on an external library. I have
+ * made an effort to clarify and simplify the algorithm, so the
+ * names and structure here don't exactly match those used by compress.
+ */
+
+struct private_data {
+ /* Input variables. */
+ const unsigned char *next_in;
+ size_t avail_in;
+ size_t consume_unnotified;
+ int bit_buffer;
+ int bits_avail;
+ size_t bytes_in_section;
+
+ /* Output variables. */
+ size_t out_block_size;
+ void *out_block;
+
+ /* Decompression status variables. */
+ int use_reset_code;
+ int end_of_stream; /* EOF status. */
+ int maxcode; /* Largest code. */
+ int maxcode_bits; /* Length of largest code. */
+ int section_end_code; /* When to increase bits. */
+ int bits; /* Current code length. */
+ int oldcode; /* Previous code. */
+ int finbyte; /* Last byte of prev code. */
+
+ /* Dictionary. */
+ int free_ent; /* Next dictionary entry. */
+ unsigned char suffix[65536];
+ uint16_t prefix[65536];
+
+ /*
+ * Scratch area for expanding dictionary entries. Note:
+ * "worst" case here comes from compressing /dev/zero: the
+ * last code in the dictionary will code a sequence of
+ * 65536-256 zero bytes. Thus, we need stack space to expand
+ * a 65280-byte dictionary entry. (Of course, 32640:1
+ * compression could also be considered the "best" case. ;-)
+ */
+ unsigned char *stackp;
+ unsigned char stack[65300];
+};
+
+static int compress_bidder_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
+static int compress_bidder_init(struct archive_read_filter *);
+static int compress_bidder_free(struct archive_read_filter_bidder *);
+
+static ssize_t compress_filter_read(struct archive_read_filter *, const void **);
+static int compress_filter_close(struct archive_read_filter *);
+
+static int getbits(struct archive_read_filter *, int n);
+static int next_code(struct archive_read_filter *);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Deprecated; remove in libarchive 4.0 */
+int
+archive_read_support_compression_compress(struct archive *a)
+{
+ return archive_read_support_filter_compress(a);
+}
+#endif
+
+int
+archive_read_support_filter_compress(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter_bidder *bidder;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_compress");
+
+ if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ bidder->data = NULL;
+ bidder->bid = compress_bidder_bid;
+ bidder->init = compress_bidder_init;
+ bidder->options = NULL;
+ bidder->free = compress_bidder_free;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Test whether we can handle this data.
+ * This logic returns zero if any part of the signature fails.
+ */
+static int
+compress_bidder_bid(struct archive_read_filter_bidder *self,
+ struct archive_read_filter *filter)
+{
+ const unsigned char *buffer;
+ ssize_t avail;
+ int bits_checked;
+
+ (void)self; /* UNUSED */
+
+ buffer = __archive_read_filter_ahead(filter, 2, &avail);
+
+ if (buffer == NULL)
+ return (0);
+
+ bits_checked = 0;
+ if (buffer[0] != 0x1F || buffer[1] != 0x9D)
+ return (0);
+ bits_checked += 16;
+
+ /*
+ * TODO: Verify more.
+ */
+
+ return (bits_checked);
+}
+
+/*
+ * Setup the callbacks.
+ */
+static int
+compress_bidder_init(struct archive_read_filter *self)
+{
+ struct private_data *state;
+ static const size_t out_block_size = 64 * 1024;
+ void *out_block;
+ int code;
+
+ self->code = ARCHIVE_COMPRESSION_COMPRESS;
+ self->name = "compress (.Z)";
+
+ state = (struct private_data *)calloc(sizeof(*state), 1);
+ out_block = malloc(out_block_size);
+ if (state == NULL || out_block == NULL) {
+ free(out_block);
+ free(state);
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate data for %s decompression",
+ self->name);
+ return (ARCHIVE_FATAL);
+ }
+
+ self->data = state;
+ state->out_block_size = out_block_size;
+ state->out_block = out_block;
+ self->read = compress_filter_read;
+ self->skip = NULL; /* not supported */
+ self->close = compress_filter_close;
+
+ /* XXX MOVE THE FOLLOWING OUT OF INIT() XXX */
+
+ (void)getbits(self, 8); /* Skip first signature byte. */
+ (void)getbits(self, 8); /* Skip second signature byte. */
+
+ code = getbits(self, 8);
+ state->maxcode_bits = code & 0x1f;
+ state->maxcode = (1 << state->maxcode_bits);
+ state->use_reset_code = code & 0x80;
+
+ /* Initialize decompressor. */
+ state->free_ent = 256;
+ state->stackp = state->stack;
+ if (state->use_reset_code)
+ state->free_ent++;
+ state->bits = 9;
+ state->section_end_code = (1<<state->bits) - 1;
+ state->oldcode = -1;
+ for (code = 255; code >= 0; code--) {
+ state->prefix[code] = 0;
+ state->suffix[code] = code;
+ }
+ next_code(self);
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Return a block of data from the decompression buffer. Decompress more
+ * as necessary.
+ */
+static ssize_t
+compress_filter_read(struct archive_read_filter *self, const void **pblock)
+{
+ struct private_data *state;
+ unsigned char *p, *start, *end;
+ int ret;
+
+ state = (struct private_data *)self->data;
+ if (state->end_of_stream) {
+ *pblock = NULL;
+ return (0);
+ }
+ p = start = (unsigned char *)state->out_block;
+ end = start + state->out_block_size;
+
+ while (p < end && !state->end_of_stream) {
+ if (state->stackp > state->stack) {
+ *p++ = *--state->stackp;
+ } else {
+ ret = next_code(self);
+ if (ret == -1)
+ state->end_of_stream = ret;
+ else if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+ }
+
+ *pblock = start;
+ return (p - start);
+}
+
+/*
+ * Clean up the reader.
+ */
+static int
+compress_bidder_free(struct archive_read_filter_bidder *self)
+{
+ self->data = NULL;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Close and release the filter.
+ */
+static int
+compress_filter_close(struct archive_read_filter *self)
+{
+ struct private_data *state = (struct private_data *)self->data;
+
+ free(state->out_block);
+ free(state);
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Process the next code and fill the stack with the expansion
+ * of the code. Returns ARCHIVE_FATAL if there is a fatal I/O or
+ * format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.
+ */
+static int
+next_code(struct archive_read_filter *self)
+{
+ struct private_data *state = (struct private_data *)self->data;
+ int code, newcode;
+
+ static int debug_buff[1024];
+ static unsigned debug_index;
+
+ code = newcode = getbits(self, state->bits);
+ if (code < 0)
+ return (code);
+
+ debug_buff[debug_index++] = code;
+ if (debug_index >= sizeof(debug_buff)/sizeof(debug_buff[0]))
+ debug_index = 0;
+
+ /* If it's a reset code, reset the dictionary. */
+ if ((code == 256) && state->use_reset_code) {
+ /*
+ * The original 'compress' implementation blocked its
+ * I/O in a manner that resulted in junk bytes being
+ * inserted after every reset. The next section skips
+ * this junk. (Yes, the number of *bytes* to skip is
+ * a function of the current *bit* length.)
+ */
+ int skip_bytes = state->bits -
+ (state->bytes_in_section % state->bits);
+ skip_bytes %= state->bits;
+ state->bits_avail = 0; /* Discard rest of this byte. */
+ while (skip_bytes-- > 0) {
+ code = getbits(self, 8);
+ if (code < 0)
+ return (code);
+ }
+ /* Now, actually do the reset. */
+ state->bytes_in_section = 0;
+ state->bits = 9;
+ state->section_end_code = (1 << state->bits) - 1;
+ state->free_ent = 257;
+ state->oldcode = -1;
+ return (next_code(self));
+ }
+
+ if (code > state->free_ent) {
+ /* An invalid code is a fatal error. */
+ archive_set_error(&(self->archive->archive), -1,
+ "Invalid compressed data");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Special case for KwKwK string. */
+ if (code >= state->free_ent) {
+ *state->stackp++ = state->finbyte;
+ code = state->oldcode;
+ }
+
+ /* Generate output characters in reverse order. */
+ while (code >= 256) {
+ *state->stackp++ = state->suffix[code];
+ code = state->prefix[code];
+ }
+ *state->stackp++ = state->finbyte = code;
+
+ /* Generate the new entry. */
+ code = state->free_ent;
+ if (code < state->maxcode && state->oldcode >= 0) {
+ state->prefix[code] = state->oldcode;
+ state->suffix[code] = state->finbyte;
+ ++state->free_ent;
+ }
+ if (state->free_ent > state->section_end_code) {
+ state->bits++;
+ state->bytes_in_section = 0;
+ if (state->bits == state->maxcode_bits)
+ state->section_end_code = state->maxcode;
+ else
+ state->section_end_code = (1 << state->bits) - 1;
+ }
+
+ /* Remember previous code. */
+ state->oldcode = newcode;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Return next 'n' bits from stream.
+ *
+ * -1 indicates end of available data.
+ */
+static int
+getbits(struct archive_read_filter *self, int n)
+{
+ struct private_data *state = (struct private_data *)self->data;
+ int code;
+ ssize_t ret;
+ static const int mask[] = {
+ 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
+ 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+ };
+
+ while (state->bits_avail < n) {
+ if (state->avail_in <= 0) {
+ if (state->consume_unnotified) {
+ __archive_read_filter_consume(self->upstream,
+ state->consume_unnotified);
+ state->consume_unnotified = 0;
+ }
+ state->next_in
+ = __archive_read_filter_ahead(self->upstream,
+ 1, &ret);
+ if (ret == 0)
+ return (-1);
+ if (ret < 0 || state->next_in == NULL)
+ return (ARCHIVE_FATAL);
+ state->consume_unnotified = state->avail_in = ret;
+ }
+ state->bit_buffer |= *state->next_in++ << state->bits_avail;
+ state->avail_in--;
+ state->bits_avail += 8;
+ state->bytes_in_section++;
+ }
+
+ code = state->bit_buffer;
+ state->bit_buffer >>= n;
+ state->bits_avail -= n;
+
+ return (code & mask[n]);
+}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_filter_gzip.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_filter_gzip.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,476 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+#ifdef HAVE_ZLIB_H
+struct private_data {
+ z_stream stream;
+ char in_stream;
+ unsigned char *out_block;
+ size_t out_block_size;
+ int64_t total_out;
+ unsigned long crc;
+ char eof; /* True = found end of compressed data. */
+};
+
+/* Gzip Filter. */
+static ssize_t gzip_filter_read(struct archive_read_filter *, const void **);
+static int gzip_filter_close(struct archive_read_filter *);
+#endif
+
+/*
+ * Note that we can detect gzip archives even if we can't decompress
+ * them. (In fact, we like detecting them because we can give better
+ * error messages.) So the bid framework here gets compiled even
+ * if zlib is unavailable.
+ *
+ * TODO: If zlib is unavailable, gzip_bidder_init() should
+ * use the compress_program framework to try to fire up an external
+ * gunzip program.
+ */
+static int gzip_bidder_bid(struct archive_read_filter_bidder *,
+ struct archive_read_filter *);
+static int gzip_bidder_init(struct archive_read_filter *);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Deprecated; remove in libarchive 4.0 */
+int
+archive_read_support_compression_gzip(struct archive *a)
+{
+ return archive_read_support_filter_gzip(a);
+}
+#endif
+
+int
+archive_read_support_filter_gzip(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter_bidder *bidder;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_gzip");
+
+ if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ bidder->data = NULL;
+ bidder->bid = gzip_bidder_bid;
+ bidder->init = gzip_bidder_init;
+ bidder->options = NULL;
+ bidder->free = NULL; /* No data, so no cleanup necessary. */
+ /* Signal the extent of gzip support with the return value here. */
+#if HAVE_ZLIB_H
+ return (ARCHIVE_OK);
+#else
+ archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ "Using external gunzip program");
+ return (ARCHIVE_WARN);
+#endif
+}
+
+/*
+ * Read and verify the header.
+ *
+ * Returns zero if the header couldn't be validated, else returns
+ * number of bytes in header. If pbits is non-NULL, it receives a
+ * count of bits verified, suitable for use by bidder.
+ */
+static int
+peek_at_header(struct archive_read_filter *filter, int *pbits)
+{
+ const unsigned char *p;
+ ssize_t avail, len;
+ int bits = 0;
+ int header_flags;
+
+ /* Start by looking at the first ten bytes of the header, which
+ * is all fixed layout. */
+ len = 10;
+ p = __archive_read_filter_ahead(filter, len, &avail);
+ if (p == NULL || avail == 0)
+ return (0);
+ /* We only support deflation- third byte must be 0x08. */
+ if (memcmp(p, "\x1F\x8B\x08", 3) != 0)
+ return (0);
+ bits += 24;
+ if ((p[3] & 0xE0)!= 0) /* No reserved flags set. */
+ return (0);
+ bits += 3;
+ header_flags = p[3];
+ /* Bytes 4-7 are mod time. */
+ /* Byte 8 is deflate flags. */
+ /* XXXX TODO: return deflate flags back to consume_header for use
+ in initializing the decompressor. */
+ /* Byte 9 is OS. */
+
+ /* Optional extra data: 2 byte length plus variable body. */
+ if (header_flags & 4) {
+ p = __archive_read_filter_ahead(filter, len + 2, &avail);
+ if (p == NULL)
+ return (0);
+ len += ((int)p[len + 1] << 8) | (int)p[len];
+ len += 2;
+ }
+
+ /* Null-terminated optional filename. */
+ if (header_flags & 8) {
+ do {
+ ++len;
+ if (avail < len)
+ p = __archive_read_filter_ahead(filter,
+ len, &avail);
+ if (p == NULL)
+ return (0);
+ } while (p[len - 1] != 0);
+ }
+
+ /* Null-terminated optional comment. */
+ if (header_flags & 16) {
+ do {
+ ++len;
+ if (avail < len)
+ p = __archive_read_filter_ahead(filter,
+ len, &avail);
+ if (p == NULL)
+ return (0);
+ } while (p[len - 1] != 0);
+ }
+
+ /* Optional header CRC */
+ if ((header_flags & 2)) {
+ p = __archive_read_filter_ahead(filter, len + 2, &avail);
+ if (p == NULL)
+ return (0);
+#if 0
+ int hcrc = ((int)p[len + 1] << 8) | (int)p[len];
+ int crc = /* XXX TODO: Compute header CRC. */;
+ if (crc != hcrc)
+ return (0);
+ bits += 16;
+#endif
+ len += 2;
+ }
+
+ if (pbits != NULL)
+ *pbits = bits;
+ return (len);
+}
+
+/*
+ * Bidder just verifies the header and returns the number of verified bits.
+ */
+static int
+gzip_bidder_bid(struct archive_read_filter_bidder *self,
+ struct archive_read_filter *filter)
+{
+ int bits_checked;
+
+ (void)self; /* UNUSED */
+
+ if (peek_at_header(filter, &bits_checked))
+ return (bits_checked);
+ return (0);
+}
+
+
+#ifndef HAVE_ZLIB_H
+
+/*
+ * If we don't have the library on this system, we can't do the
+ * decompression directly. We can, however, try to run gunzip
+ * in case that's available.
+ */
+static int
+gzip_bidder_init(struct archive_read_filter *self)
+{
+ int r;
+
+ r = __archive_read_program(self, "gunzip");
+ /* Note: We set the format here even if __archive_read_program()
+ * above fails. We do, after all, know what the format is
+ * even if we weren't able to read it. */
+ self->code = ARCHIVE_COMPRESSION_GZIP;
+ self->name = "gzip";
+ return (r);
+}
+
+#else
+
+/*
+ * Initialize the filter object.
+ */
+static int
+gzip_bidder_init(struct archive_read_filter *self)
+{
+ struct private_data *state;
+ static const size_t out_block_size = 64 * 1024;
+ void *out_block;
+
+ self->code = ARCHIVE_COMPRESSION_GZIP;
+ self->name = "gzip";
+
+ state = (struct private_data *)calloc(sizeof(*state), 1);
+ out_block = (unsigned char *)malloc(out_block_size);
+ if (state == NULL || out_block == NULL) {
+ free(out_block);
+ free(state);
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate data for gzip decompression");
+ return (ARCHIVE_FATAL);
+ }
+
+ self->data = state;
+ state->out_block_size = out_block_size;
+ state->out_block = out_block;
+ self->read = gzip_filter_read;
+ self->skip = NULL; /* not supported */
+ self->close = gzip_filter_close;
+
+ state->in_stream = 0; /* We're not actually within a stream yet. */
+
+ return (ARCHIVE_OK);
+}
+
+static int
+consume_header(struct archive_read_filter *self)
+{
+ struct private_data *state;
+ ssize_t avail;
+ size_t len;
+ int ret;
+
+ state = (struct private_data *)self->data;
+
+ /* If this is a real header, consume it. */
+ len = peek_at_header(self->upstream, NULL);
+ if (len == 0)
+ return (ARCHIVE_EOF);
+ __archive_read_filter_consume(self->upstream, len);
+
+ /* Initialize CRC accumulator. */
+ state->crc = crc32(0L, NULL, 0);
+
+ /* Initialize compression library. */
+ state->stream.next_in = (unsigned char *)(uintptr_t)
+ __archive_read_filter_ahead(self->upstream, 1, &avail);
+ state->stream.avail_in = avail;
+ ret = inflateInit2(&(state->stream),
+ -15 /* Don't check for zlib header */);
+
+ /* Decipher the error code. */
+ switch (ret) {
+ case Z_OK:
+ state->in_stream = 1;
+ return (ARCHIVE_OK);
+ case Z_STREAM_ERROR:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "invalid setup parameter");
+ break;
+ case Z_MEM_ERROR:
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Internal error initializing compression library: "
+ "out of memory");
+ break;
+ case Z_VERSION_ERROR:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "invalid library version");
+ break;
+ default:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ " Zlib error %d", ret);
+ break;
+ }
+ return (ARCHIVE_FATAL);
+}
+
+static int
+consume_trailer(struct archive_read_filter *self)
+{
+ struct private_data *state;
+ const unsigned char *p;
+ ssize_t avail;
+
+ state = (struct private_data *)self->data;
+
+ state->in_stream = 0;
+ switch (inflateEnd(&(state->stream))) {
+ case Z_OK:
+ break;
+ default:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up gzip decompressor");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* GZip trailer is a fixed 8 byte structure. */
+ p = __archive_read_filter_ahead(self->upstream, 8, &avail);
+ if (p == NULL || avail == 0)
+ return (ARCHIVE_FATAL);
+
+ /* XXX TODO: Verify the length and CRC. */
+
+ /* We've verified the trailer, so consume it now. */
+ __archive_read_filter_consume(self->upstream, 8);
+
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+gzip_filter_read(struct archive_read_filter *self, const void **p)
+{
+ struct private_data *state;
+ size_t decompressed;
+ ssize_t avail_in;
+ int ret;
+
+ state = (struct private_data *)self->data;
+
+ /* Empty our output buffer. */
+ state->stream.next_out = state->out_block;
+ state->stream.avail_out = state->out_block_size;
+
+ /* Try to fill the output buffer. */
+ while (state->stream.avail_out > 0 && !state->eof) {
+ /* If we're not in a stream, read a header
+ * and initialize the decompression library. */
+ if (!state->in_stream) {
+ ret = consume_header(self);
+ if (ret == ARCHIVE_EOF) {
+ state->eof = 1;
+ break;
+ }
+ if (ret < ARCHIVE_OK)
+ return (ret);
+ }
+
+ /* Peek at the next available data. */
+ /* ZLib treats stream.next_in as const but doesn't declare
+ * it so, hence this ugly cast. */
+ state->stream.next_in = (unsigned char *)(uintptr_t)
+ __archive_read_filter_ahead(self->upstream, 1, &avail_in);
+ if (state->stream.next_in == NULL) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "truncated gzip input");
+ return (ARCHIVE_FATAL);
+ }
+ state->stream.avail_in = avail_in;
+
+ /* Decompress and consume some of that data. */
+ ret = inflate(&(state->stream), 0);
+ switch (ret) {
+ case Z_OK: /* Decompressor made some progress. */
+ __archive_read_filter_consume(self->upstream,
+ avail_in - state->stream.avail_in);
+ break;
+ case Z_STREAM_END: /* Found end of stream. */
+ __archive_read_filter_consume(self->upstream,
+ avail_in - state->stream.avail_in);
+ /* Consume the stream trailer; release the
+ * decompression library. */
+ ret = consume_trailer(self);
+ if (ret < ARCHIVE_OK)
+ return (ret);
+ break;
+ default:
+ /* Return an error. */
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "gzip decompression failed");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ /* We've read as much as we can. */
+ decompressed = state->stream.next_out - state->out_block;
+ state->total_out += decompressed;
+ if (decompressed == 0)
+ *p = NULL;
+ else
+ *p = state->out_block;
+ return (decompressed);
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+gzip_filter_close(struct archive_read_filter *self)
+{
+ struct private_data *state;
+ int ret;
+
+ state = (struct private_data *)self->data;
+ ret = ARCHIVE_OK;
+
+ if (state->in_stream) {
+ switch (inflateEnd(&(state->stream))) {
+ case Z_OK:
+ break;
+ default:
+ archive_set_error(&(self->archive->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up gzip compressor");
+ ret = ARCHIVE_FATAL;
+ }
+ }
+
+ free(state->out_block);
+ free(state);
+ return (ret);
+}
+
+#endif /* HAVE_ZLIB_H */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_filter_none.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_filter_none.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive.h"
+#include "archive_private.h"
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Deprecated; remove in libarchive 4.0 */
+int
+archive_read_support_compression_none(struct archive *a)
+{
+ return archive_read_support_filter_none(a);
+}
+#endif
+
+/*
+ * Uncompressed streams are handled implicitly by the read core,
+ * so this is now a no-op.
+ */
+int
+archive_read_support_filter_none(struct archive *a)
+{
+ archive_check_magic(a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_none");
+
+ return (ARCHIVE_OK);
+}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_filter_program.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_filter_program.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,476 @@
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Deprecated; remove in libarchive 4.0 */
+int
+archive_read_support_compression_program(struct archive *a, const char *cmd)
+{
+ return archive_read_support_filter_program(a, cmd);
+}
+
+int
+archive_read_support_compression_program_signature(struct archive *a,
+ const char *cmd, const void *signature, size_t signature_len)
+{
+ return archive_read_support_filter_program_signature(a,
+ cmd, signature, signature_len);
+}
+#endif
+
+int
+archive_read_support_filter_program(struct archive *a, const char *cmd)
+{
+ return (archive_read_support_filter_program_signature(a, cmd, NULL, 0));
+}
+
+
+/* This capability is only available on POSIX systems. */
+#if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
+ !(defined(HAVE_FORK) || defined(HAVE_VFORK))) && (!defined(_WIN32) || defined(__CYGWIN__))
+
+/*
+ * On non-Posix systems, allow the program to build, but choke if
+ * this function is actually invoked.
+ */
+int
+archive_read_support_filter_program_signature(struct archive *_a,
+ const char *cmd, const void *signature, size_t signature_len)
+{
+ (void)_a; /* UNUSED */
+ (void)cmd; /* UNUSED */
+ (void)signature; /* UNUSED */
+ (void)signature_len; /* UNUSED */
+
+ archive_set_error(_a, -1,
+ "External compression programs not supported on this platform");
+ return (ARCHIVE_FATAL);
+}
+
+int
+__archive_read_program(struct archive_read_filter *self, const char *cmd)
+{
+ (void)self; /* UNUSED */
+ (void)cmd; /* UNUSED */
+
+ archive_set_error(&self->archive->archive, -1,
+ "External compression programs not supported on this platform");
+ return (ARCHIVE_FATAL);
+}
+
+#else
+
+#include "filter_fork.h"
+
+/*
+ * The bidder object stores the command and the signature to watch for.
+ * The 'inhibit' entry here is used to ensure that unchecked filters never
+ * bid twice in the same pipeline.
+ */
+struct program_bidder {
+ char *cmd;
+ void *signature;
+ size_t signature_len;
+ int inhibit;
+};
+
+static int program_bidder_bid(struct archive_read_filter_bidder *,
+ struct archive_read_filter *upstream);
+static int program_bidder_init(struct archive_read_filter *);
+static int program_bidder_free(struct archive_read_filter_bidder *);
+
+/*
+ * The actual filter needs to track input and output data.
+ */
+struct program_filter {
+ char *description;
+ pid_t child;
+ int exit_status;
+ int waitpid_return;
+ int child_stdin, child_stdout;
+
+ char *out_buf;
+ size_t out_buf_len;
+};
+
+static ssize_t program_filter_read(struct archive_read_filter *,
+ const void **);
+static int program_filter_close(struct archive_read_filter *);
+
+int
+archive_read_support_filter_program_signature(struct archive *_a,
+ const char *cmd, const void *signature, size_t signature_len)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter_bidder *bidder;
+ struct program_bidder *state;
+
+ /*
+ * Get a bidder object from the read core.
+ */
+ if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ /*
+ * Allocate our private state.
+ */
+ state = (struct program_bidder *)calloc(sizeof (*state), 1);
+ if (state == NULL)
+ return (ARCHIVE_FATAL);
+ state->cmd = strdup(cmd);
+ if (signature != NULL && signature_len > 0) {
+ state->signature_len = signature_len;
+ state->signature = malloc(signature_len);
+ memcpy(state->signature, signature, signature_len);
+ }
+
+ /*
+ * Fill in the bidder object.
+ */
+ bidder->data = state;
+ bidder->bid = program_bidder_bid;
+ bidder->init = program_bidder_init;
+ bidder->options = NULL;
+ bidder->free = program_bidder_free;
+ return (ARCHIVE_OK);
+}
+
+static int
+program_bidder_free(struct archive_read_filter_bidder *self)
+{
+ struct program_bidder *state = (struct program_bidder *)self->data;
+ free(state->cmd);
+ free(state->signature);
+ free(self->data);
+ return (ARCHIVE_OK);
+}
+
+/*
+ * If we do have a signature, bid only if that matches.
+ *
+ * If there's no signature, we bid INT_MAX the first time
+ * we're called, then never bid again.
+ */
+static int
+program_bidder_bid(struct archive_read_filter_bidder *self,
+ struct archive_read_filter *upstream)
+{
+ struct program_bidder *state = self->data;
+ const char *p;
+
+ /* If we have a signature, use that to match. */
+ if (state->signature_len > 0) {
+ p = __archive_read_filter_ahead(upstream,
+ state->signature_len, NULL);
+ if (p == NULL)
+ return (0);
+ /* No match, so don't bid. */
+ if (memcmp(p, state->signature, state->signature_len) != 0)
+ return (0);
+ return ((int)state->signature_len * 8);
+ }
+
+ /* Otherwise, bid once and then never bid again. */
+ if (state->inhibit)
+ return (0);
+ state->inhibit = 1;
+ return (INT_MAX);
+}
+
+/*
+ * Shut down the child, return ARCHIVE_OK if it exited normally.
+ *
+ * Note that the return value is sticky; if we're called again,
+ * we won't reap the child again, but we will return the same status
+ * (including error message if the child came to a bad end).
+ */
+static int
+child_stop(struct archive_read_filter *self, struct program_filter *state)
+{
+ /* Close our side of the I/O with the child. */
+ if (state->child_stdin != -1) {
+ close(state->child_stdin);
+ state->child_stdin = -1;
+ }
+ if (state->child_stdout != -1) {
+ close(state->child_stdout);
+ state->child_stdout = -1;
+ }
+
+ if (state->child != 0) {
+ /* Reap the child. */
+ do {
+ state->waitpid_return
+ = waitpid(state->child, &state->exit_status, 0);
+ } while (state->waitpid_return == -1 && errno == EINTR);
+ state->child = 0;
+ }
+
+ if (state->waitpid_return < 0) {
+ /* waitpid() failed? This is ugly. */
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "Child process exited badly");
+ return (ARCHIVE_WARN);
+ }
+
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ if (WIFSIGNALED(state->exit_status)) {
+#ifdef SIGPIPE
+ /* If the child died because we stopped reading before
+ * it was done, that's okay. Some archive formats
+ * have padding at the end that we routinely ignore. */
+ /* The alternative to this would be to add a step
+ * before close(child_stdout) above to read from the
+ * child until the child has no more to write. */
+ if (WTERMSIG(state->exit_status) == SIGPIPE)
+ return (ARCHIVE_OK);
+#endif
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "Child process exited with signal %d",
+ WTERMSIG(state->exit_status));
+ return (ARCHIVE_WARN);
+ }
+#endif /* !_WIN32 || __CYGWIN__ */
+
+ if (WIFEXITED(state->exit_status)) {
+ if (WEXITSTATUS(state->exit_status) == 0)
+ return (ARCHIVE_OK);
+
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Child process exited with status %d",
+ WEXITSTATUS(state->exit_status));
+ return (ARCHIVE_WARN);
+ }
+
+ return (ARCHIVE_WARN);
+}
+
+/*
+ * Use select() to decide whether the child is ready for read or write.
+ */
+static ssize_t
+child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
+{
+ struct program_filter *state = self->data;
+ ssize_t ret, requested, avail;
+ const char *p;
+
+ requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
+
+ for (;;) {
+ do {
+ ret = read(state->child_stdout, buf, requested);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret > 0)
+ return (ret);
+ if (ret == 0 || (ret == -1 && errno == EPIPE))
+ /* Child has closed its output; reap the child
+ * and return the status. */
+ return (child_stop(self, state));
+ if (ret == -1 && errno != EAGAIN)
+ return (-1);
+
+ if (state->child_stdin == -1) {
+ /* Block until child has some I/O ready. */
+ __archive_check_child(state->child_stdin,
+ state->child_stdout);
+ continue;
+ }
+
+ /* Get some more data from upstream. */
+ p = __archive_read_filter_ahead(self->upstream, 1, &avail);
+ if (p == NULL) {
+ close(state->child_stdin);
+ state->child_stdin = -1;
+ fcntl(state->child_stdout, F_SETFL, 0);
+ if (avail < 0)
+ return (avail);
+ continue;
+ }
+
+ do {
+ ret = write(state->child_stdin, p, avail);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret > 0) {
+ /* Consume whatever we managed to write. */
+ __archive_read_filter_consume(self->upstream, ret);
+ } else if (ret == -1 && errno == EAGAIN) {
+ /* Block until child has some I/O ready. */
+ __archive_check_child(state->child_stdin,
+ state->child_stdout);
+ } else {
+ /* Write failed. */
+ close(state->child_stdin);
+ state->child_stdin = -1;
+ fcntl(state->child_stdout, F_SETFL, 0);
+ /* If it was a bad error, we're done; otherwise
+ * it was EPIPE or EOF, and we can still read
+ * from the child. */
+ if (ret == -1 && errno != EPIPE)
+ return (-1);
+ }
+ }
+}
+
+int
+__archive_read_program(struct archive_read_filter *self, const char *cmd)
+{
+ struct program_filter *state;
+ static const size_t out_buf_len = 65536;
+ char *out_buf;
+ char *description;
+ const char *prefix = "Program: ";
+
+ state = (struct program_filter *)calloc(1, sizeof(*state));
+ out_buf = (char *)malloc(out_buf_len);
+ description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
+ if (state == NULL || out_buf == NULL || description == NULL) {
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate input data");
+ free(state);
+ free(out_buf);
+ free(description);
+ return (ARCHIVE_FATAL);
+ }
+
+ self->code = ARCHIVE_COMPRESSION_PROGRAM;
+ state->description = description;
+ strcpy(state->description, prefix);
+ strcat(state->description, cmd);
+ self->name = state->description;
+
+ state->out_buf = out_buf;
+ state->out_buf_len = out_buf_len;
+
+ if ((state->child = __archive_create_child(cmd,
+ &state->child_stdin, &state->child_stdout)) == -1) {
+ free(state->out_buf);
+ free(state);
+ archive_set_error(&self->archive->archive, EINVAL,
+ "Can't initialize filter; unable to run program \"%s\"", cmd);
+ return (ARCHIVE_FATAL);
+ }
+
+ self->data = state;
+ self->read = program_filter_read;
+ self->skip = NULL;
+ self->close = program_filter_close;
+
+ /* XXX Check that we can read at least one byte? */
+ return (ARCHIVE_OK);
+}
+
+static int
+program_bidder_init(struct archive_read_filter *self)
+{
+ struct program_bidder *bidder_state;
+
+ bidder_state = (struct program_bidder *)self->bidder->data;
+ return (__archive_read_program(self, bidder_state->cmd));
+}
+
+static ssize_t
+program_filter_read(struct archive_read_filter *self, const void **buff)
+{
+ struct program_filter *state;
+ ssize_t bytes;
+ size_t total;
+ char *p;
+
+ state = (struct program_filter *)self->data;
+
+ total = 0;
+ p = state->out_buf;
+ while (state->child_stdout != -1 && total < state->out_buf_len) {
+ bytes = child_read(self, p, state->out_buf_len - total);
+ if (bytes < 0)
+ /* No recovery is possible if we can no longer
+ * read from the child. */
+ return (ARCHIVE_FATAL);
+ if (bytes == 0)
+ /* We got EOF from the child. */
+ break;
+ total += bytes;
+ p += bytes;
+ }
+
+ *buff = state->out_buf;
+ return (total);
+}
+
+static int
+program_filter_close(struct archive_read_filter *self)
+{
+ struct program_filter *state;
+ int e;
+
+ state = (struct program_filter *)self->data;
+ e = child_stop(self, state);
+
+ /* Release our private data. */
+ free(state->out_buf);
+ free(state->description);
+ free(state);
+
+ return (e);
+}
+
+#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_filter_rpm.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_filter_rpm.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,288 @@
+/*-
+ * Copyright (c) 2009 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_endian.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+struct rpm {
+ int64_t total_in;
+ size_t hpos;
+ size_t hlen;
+ unsigned char header[16];
+ enum {
+ ST_LEAD, /* Skipping 'Lead' section. */
+ ST_HEADER, /* Reading 'Header' section;
+ * first 16 bytes. */
+ ST_HEADER_DATA, /* Skipping 'Header' section. */
+ ST_PADDING, /* Skipping padding data after the
+ * 'Header' section. */
+ ST_ARCHIVE /* Reading 'Archive' section. */
+ } state;
+ int first_header;
+};
+#define RPM_LEAD_SIZE 96 /* Size of 'Lead' section. */
+
+static int rpm_bidder_bid(struct archive_read_filter_bidder *,
+ struct archive_read_filter *);
+static int rpm_bidder_init(struct archive_read_filter *);
+
+static ssize_t rpm_filter_read(struct archive_read_filter *,
+ const void **);
+static int rpm_filter_close(struct archive_read_filter *);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Deprecated; remove in libarchive 4.0 */
+int
+archive_read_support_compression_rpm(struct archive *a)
+{
+ return archive_read_support_filter_rpm(a);
+}
+#endif
+
+int
+archive_read_support_filter_rpm(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter_bidder *bidder;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_rpm");
+
+ if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ bidder->data = NULL;
+ bidder->bid = rpm_bidder_bid;
+ bidder->init = rpm_bidder_init;
+ bidder->options = NULL;
+ bidder->free = NULL;
+ return (ARCHIVE_OK);
+}
+
+static int
+rpm_bidder_bid(struct archive_read_filter_bidder *self,
+ struct archive_read_filter *filter)
+{
+ const unsigned char *b;
+ ssize_t avail;
+ int bits_checked;
+
+ (void)self; /* UNUSED */
+
+ b = __archive_read_filter_ahead(filter, 8, &avail);
+ if (b == NULL)
+ return (0);
+
+ bits_checked = 0;
+ /*
+ * Verify Header Magic Bytes : 0XED 0XAB 0XEE 0XDB
+ */
+ if (memcmp(b, "\xED\xAB\xEE\xDB", 4) != 0)
+ return (0);
+ bits_checked += 32;
+ /*
+ * Check major version.
+ */
+ if (b[4] != 3 && b[4] != 4)
+ return (0);
+ bits_checked += 8;
+ /*
+ * Check package type; binary or source.
+ */
+ if (b[6] != 0)
+ return (0);
+ bits_checked += 8;
+ if (b[7] != 0 && b[7] != 1)
+ return (0);
+ bits_checked += 8;
+
+ return (bits_checked);
+}
+
+static int
+rpm_bidder_init(struct archive_read_filter *self)
+{
+ struct rpm *rpm;
+
+ self->code = ARCHIVE_COMPRESSION_RPM;
+ self->name = "rpm";
+ self->read = rpm_filter_read;
+ self->skip = NULL; /* not supported */
+ self->close = rpm_filter_close;
+
+ rpm = (struct rpm *)calloc(sizeof(*rpm), 1);
+ if (rpm == NULL) {
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate data for rpm");
+ return (ARCHIVE_FATAL);
+ }
+
+ self->data = rpm;
+ rpm->state = ST_LEAD;
+
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+rpm_filter_read(struct archive_read_filter *self, const void **buff)
+{
+ struct rpm *rpm;
+ const unsigned char *b;
+ ssize_t avail_in, total;
+ size_t used, n;
+ uint32_t section;
+ uint32_t bytes;
+
+ rpm = (struct rpm *)self->data;
+ *buff = NULL;
+ total = avail_in = 0;
+ b = NULL;
+ used = 0;
+ do {
+ if (b == NULL) {
+ b = __archive_read_filter_ahead(self->upstream, 1,
+ &avail_in);
+ if (b == NULL) {
+ if (avail_in < 0)
+ return (ARCHIVE_FATAL);
+ else
+ break;
+ }
+ }
+
+ switch (rpm->state) {
+ case ST_LEAD:
+ if (rpm->total_in + avail_in < RPM_LEAD_SIZE)
+ used += avail_in;
+ else {
+ n = RPM_LEAD_SIZE - rpm->total_in;
+ used += n;
+ b += n;
+ rpm->state = ST_HEADER;
+ rpm->hpos = 0;
+ rpm->hlen = 0;
+ rpm->first_header = 1;
+ }
+ break;
+ case ST_HEADER:
+ n = 16 - rpm->hpos;
+ if (n > avail_in - used)
+ n = avail_in - used;
+ memcpy(rpm->header+rpm->hpos, b, n);
+ b += n;
+ used += n;
+ rpm->hpos += n;
+
+ if (rpm->hpos == 16) {
+ if (rpm->header[0] != 0x8e ||
+ rpm->header[1] != 0xad ||
+ rpm->header[2] != 0xe8 ||
+ rpm->header[3] != 0x01) {
+ if (rpm->first_header) {
+ archive_set_error(
+ &self->archive->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unrecoginized rpm header");
+ return (ARCHIVE_FATAL);
+ }
+ rpm->state = ST_ARCHIVE;
+ *buff = rpm->header;
+ total = rpm->hpos;
+ break;
+ }
+ /* Calculate 'Header' length. */
+ section = archive_be32dec(rpm->header+8);
+ bytes = archive_be32dec(rpm->header+12);
+ rpm->hlen = 16 + section * 16 + bytes;
+ rpm->state = ST_HEADER_DATA;
+ rpm->first_header = 0;
+ }
+ break;
+ case ST_HEADER_DATA:
+ n = rpm->hlen - rpm->hpos;
+ if (n > avail_in - used)
+ n = avail_in - used;
+ b += n;
+ used += n;
+ rpm->hpos += n;
+ if (rpm->hpos == rpm->hlen)
+ rpm->state = ST_PADDING;
+ break;
+ case ST_PADDING:
+ while (used < (size_t)avail_in) {
+ if (*b != 0) {
+ /* Read next header. */
+ rpm->state = ST_HEADER;
+ rpm->hpos = 0;
+ rpm->hlen = 0;
+ break;
+ }
+ b++;
+ used++;
+ }
+ break;
+ case ST_ARCHIVE:
+ *buff = b;
+ total = avail_in;
+ used = avail_in;
+ break;
+ }
+ if (used == (size_t)avail_in) {
+ rpm->total_in += used;
+ __archive_read_filter_consume(self->upstream, used);
+ b = NULL;
+ used = 0;
+ }
+ } while (total == 0 && avail_in > 0);
+
+ if (used > 0 && b != NULL) {
+ rpm->total_in += used;
+ __archive_read_filter_consume(self->upstream, used);
+ }
+ return (total);
+}
+
+static int
+rpm_filter_close(struct archive_read_filter *self)
+{
+ struct rpm *rpm;
+
+ rpm = (struct rpm *)self->data;
+ free(rpm);
+
+ return (ARCHIVE_OK);
+}
+
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_filter_uu.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_filter_uu.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,680 @@
+/*-
+ * Copyright (c) 2009-2011 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+/* Maximum lookahead during bid phase */
+#define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */
+
+struct uudecode {
+ int64_t total;
+ unsigned char *in_buff;
+#define IN_BUFF_SIZE (1024)
+ int in_cnt;
+ size_t in_allocated;
+ unsigned char *out_buff;
+#define OUT_BUFF_SIZE (64 * 1024)
+ int state;
+#define ST_FIND_HEAD 0
+#define ST_READ_UU 1
+#define ST_UUEND 2
+#define ST_READ_BASE64 3
+};
+
+static int uudecode_bidder_bid(struct archive_read_filter_bidder *,
+ struct archive_read_filter *filter);
+static int uudecode_bidder_init(struct archive_read_filter *);
+
+static ssize_t uudecode_filter_read(struct archive_read_filter *,
+ const void **);
+static int uudecode_filter_close(struct archive_read_filter *);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Deprecated; remove in libarchive 4.0 */
+int
+archive_read_support_compression_uu(struct archive *a)
+{
+ return archive_read_support_filter_uu(a);
+}
+#endif
+
+int
+archive_read_support_filter_uu(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter_bidder *bidder;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_uu");
+
+ if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ bidder->data = NULL;
+ bidder->bid = uudecode_bidder_bid;
+ bidder->init = uudecode_bidder_init;
+ bidder->options = NULL;
+ bidder->free = NULL;
+ return (ARCHIVE_OK);
+}
+
+static const unsigned char ascii[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', 0, 0, '\r', 0, 0, /* 00 - 0F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
+};
+
+static const unsigned char uuchar[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
+};
+
+static const unsigned char base64[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, /* 20 - 2F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 30 - 3F */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 50 - 5F */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 - 7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
+};
+
+static const int base64num[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 62, 0, 0, 0, 63, /* 20 - 2F */
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 0, 0, 0, 0, 0, 0, /* 30 - 3F */
+ 0, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, /* 40 - 4F */
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 0, 0, 0, 0, 0, /* 50 - 5F */
+ 0, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 0, 0, 0, 0, 0, /* 70 - 7F */
+};
+
+static ssize_t
+get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize)
+{
+ ssize_t len;
+
+ len = 0;
+ while (len < avail) {
+ switch (ascii[*b]) {
+ case 0: /* Non-ascii character or control character. */
+ if (nlsize != NULL)
+ *nlsize = 0;
+ return (-1);
+ case '\r':
+ if (avail-len > 1 && b[1] == '\n') {
+ if (nlsize != NULL)
+ *nlsize = 2;
+ return (len+2);
+ }
+ /* FALL THROUGH */
+ case '\n':
+ if (nlsize != NULL)
+ *nlsize = 1;
+ return (len+1);
+ case 1:
+ b++;
+ len++;
+ break;
+ }
+ }
+ if (nlsize != NULL)
+ *nlsize = 0;
+ return (avail);
+}
+
+static ssize_t
+bid_get_line(struct archive_read_filter *filter,
+ const unsigned char **b, ssize_t *avail, ssize_t *ravail,
+ ssize_t *nl, size_t* nbytes_read)
+{
+ ssize_t len;
+ int quit;
+
+ quit = 0;
+ if (*avail == 0) {
+ *nl = 0;
+ len = 0;
+ } else
+ len = get_line(*b, *avail, nl);
+
+ /*
+ * Read bytes more while it does not reach the end of line.
+ */
+ while (*nl == 0 && len == *avail && !quit &&
+ *nbytes_read < UUENCODE_BID_MAX_READ) {
+ ssize_t diff = *ravail - *avail;
+ size_t nbytes_req = (*ravail+1023) & ~1023U;
+ ssize_t tested;
+
+ /* Increase reading bytes if it is not enough to at least
+ * new two lines. */
+ if (nbytes_req < (size_t)*ravail + 160)
+ nbytes_req <<= 1;
+
+ *b = __archive_read_filter_ahead(filter, nbytes_req, avail);
+ if (*b == NULL) {
+ if (*ravail >= *avail)
+ return (0);
+ /* Reading bytes reaches the end of a stream. */
+ *b = __archive_read_filter_ahead(filter, *avail, avail);
+ quit = 1;
+ }
+ *nbytes_read = *avail;
+ *ravail = *avail;
+ *b += diff;
+ *avail -= diff;
+ tested = len;/* Skip some bytes we already determinated. */
+ len = get_line(*b + tested, *avail - tested, nl);
+ if (len >= 0)
+ len += tested;
+ }
+ return (len);
+}
+
+#define UUDECODE(c) (((c) - 0x20) & 0x3f)
+
+static int
+uudecode_bidder_bid(struct archive_read_filter_bidder *self,
+ struct archive_read_filter *filter)
+{
+ const unsigned char *b;
+ ssize_t avail, ravail;
+ ssize_t len, nl;
+ int l;
+ int firstline;
+ size_t nbytes_read;
+
+ (void)self; /* UNUSED */
+
+ b = __archive_read_filter_ahead(filter, 1, &avail);
+ if (b == NULL)
+ return (0);
+
+ firstline = 20;
+ ravail = avail;
+ nbytes_read = avail;
+ for (;;) {
+ len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
+ if (len < 0 || nl == 0)
+ return (0); /* No match found. */
+ if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
+ l = 6;
+ else if (len -nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0)
+ l = 13;
+ else
+ l = 0;
+
+ if (l > 0 && (b[l] < '0' || b[l] > '7' ||
+ b[l+1] < '0' || b[l+1] > '7' ||
+ b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' '))
+ l = 0;
+
+ b += len;
+ avail -= len;
+ if (l)
+ break;
+ firstline = 0;
+
+ /* Do not read more than UUENCODE_BID_MAX_READ bytes */
+ if (nbytes_read >= UUENCODE_BID_MAX_READ)
+ return (0);
+ }
+ if (!avail)
+ return (0);
+ len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
+ if (len < 0 || nl == 0)
+ return (0);/* There are non-ascii characters. */
+ avail -= len;
+
+ if (l == 6) {
+ if (!uuchar[*b])
+ return (0);
+ /* Get a length of decoded bytes. */
+ l = UUDECODE(*b++); len--;
+ if (l > 45)
+ /* Normally, maximum length is 45(character 'M'). */
+ return (0);
+ while (l && len-nl > 0) {
+ if (l > 0) {
+ if (!uuchar[*b++])
+ return (0);
+ if (!uuchar[*b++])
+ return (0);
+ len -= 2;
+ --l;
+ }
+ if (l > 0) {
+ if (!uuchar[*b++])
+ return (0);
+ --len;
+ --l;
+ }
+ if (l > 0) {
+ if (!uuchar[*b++])
+ return (0);
+ --len;
+ --l;
+ }
+ }
+ if (len-nl < 0)
+ return (0);
+ if (len-nl == 1 &&
+ (uuchar[*b] || /* Check sum. */
+ (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */
+ ++b;
+ --len;
+ }
+ b += nl;
+ if (avail && uuchar[*b])
+ return (firstline+30);
+ }
+ if (l == 13) {
+ while (len-nl > 0) {
+ if (!base64[*b++])
+ return (0);
+ --len;
+ }
+ b += nl;
+
+ if (avail >= 5 && memcmp(b, "====\n", 5) == 0)
+ return (firstline+40);
+ if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)
+ return (firstline+40);
+ if (avail > 0 && base64[*b])
+ return (firstline+30);
+ }
+
+ return (0);
+}
+
+static int
+uudecode_bidder_init(struct archive_read_filter *self)
+{
+ struct uudecode *uudecode;
+ void *out_buff;
+ void *in_buff;
+
+ self->code = ARCHIVE_COMPRESSION_UU;
+ self->name = "uu";
+ self->read = uudecode_filter_read;
+ self->skip = NULL; /* not supported */
+ self->close = uudecode_filter_close;
+
+ uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1);
+ out_buff = malloc(OUT_BUFF_SIZE);
+ in_buff = malloc(IN_BUFF_SIZE);
+ if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate data for uudecode");
+ free(uudecode);
+ free(out_buff);
+ free(in_buff);
+ return (ARCHIVE_FATAL);
+ }
+
+ self->data = uudecode;
+ uudecode->in_buff = in_buff;
+ uudecode->in_cnt = 0;
+ uudecode->in_allocated = IN_BUFF_SIZE;
+ uudecode->out_buff = out_buff;
+ uudecode->state = ST_FIND_HEAD;
+
+ return (ARCHIVE_OK);
+}
+
+static int
+ensure_in_buff_size(struct archive_read_filter *self,
+ struct uudecode *uudecode, size_t size)
+{
+
+ if (size > uudecode->in_allocated) {
+ unsigned char *ptr;
+ size_t newsize;
+
+ /*
+ * Calculate a new buffer size for in_buff.
+ * Increase its value until it has enough size we need.
+ */
+ newsize = uudecode->in_allocated;
+ do {
+ if (newsize < IN_BUFF_SIZE*32)
+ newsize <<= 1;
+ else
+ newsize += IN_BUFF_SIZE;
+ } while (size > newsize);
+ /* Allocate the new buffer. */
+ ptr = malloc(newsize);
+ if (ptr == NULL) {
+ free(ptr);
+ archive_set_error(&self->archive->archive,
+ ENOMEM,
+ "Can't allocate data for uudecode");
+ return (ARCHIVE_FATAL);
+ }
+ /* Move the remaining data in in_buff into the new buffer. */
+ if (uudecode->in_cnt)
+ memmove(ptr, uudecode->in_buff, uudecode->in_cnt);
+ /* Replace in_buff with the new buffer. */
+ free(uudecode->in_buff);
+ uudecode->in_buff = ptr;
+ uudecode->in_allocated = newsize;
+ }
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+uudecode_filter_read(struct archive_read_filter *self, const void **buff)
+{
+ struct uudecode *uudecode;
+ const unsigned char *b, *d;
+ unsigned char *out;
+ ssize_t avail_in, ravail;
+ ssize_t used;
+ ssize_t total;
+ ssize_t len, llen, nl;
+
+ uudecode = (struct uudecode *)self->data;
+
+read_more:
+ d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);
+ if (d == NULL && avail_in < 0)
+ return (ARCHIVE_FATAL);
+ /* Quiet a code analyzer; make sure avail_in must be zero
+ * when d is NULL. */
+ if (d == NULL)
+ avail_in = 0;
+ used = 0;
+ total = 0;
+ out = uudecode->out_buff;
+ ravail = avail_in;
+ if (uudecode->in_cnt) {
+ /*
+ * If there is remaining data which is saved by
+ * previous calling, use it first.
+ */
+ if (ensure_in_buff_size(self, uudecode,
+ avail_in + uudecode->in_cnt) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ memcpy(uudecode->in_buff + uudecode->in_cnt,
+ d, avail_in);
+ d = uudecode->in_buff;
+ avail_in += uudecode->in_cnt;
+ uudecode->in_cnt = 0;
+ }
+ for (;used < avail_in; d += llen, used += llen) {
+ int l, body;
+
+ b = d;
+ len = get_line(b, avail_in - used, &nl);
+ if (len < 0) {
+ /* Non-ascii character is found. */
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Insufficient compressed data");
+ return (ARCHIVE_FATAL);
+ }
+ llen = len;
+ if (nl == 0) {
+ /*
+ * Save remaining data which does not contain
+ * NL('\n','\r').
+ */
+ if (ensure_in_buff_size(self, uudecode, len)
+ != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ if (uudecode->in_buff != b)
+ memmove(uudecode->in_buff, b, len);
+ uudecode->in_cnt = len;
+ if (total == 0) {
+ /* Do not return 0; it means end-of-file.
+ * We should try to read bytes more. */
+ __archive_read_filter_consume(
+ self->upstream, ravail);
+ goto read_more;
+ }
+ break;
+ }
+ switch (uudecode->state) {
+ default:
+ case ST_FIND_HEAD:
+ /* Do not read more than UUENCODE_BID_MAX_READ bytes */
+ if (total + len >= UUENCODE_BID_MAX_READ) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid format data");
+ return (ARCHIVE_FATAL);
+ }
+ if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
+ l = 6;
+ else if (len - nl >= 18 &&
+ memcmp(b, "begin-base64 ", 13) == 0)
+ l = 13;
+ else
+ l = 0;
+ if (l != 0 && b[l] >= '0' && b[l] <= '7' &&
+ b[l+1] >= '0' && b[l+1] <= '7' &&
+ b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') {
+ if (l == 6)
+ uudecode->state = ST_READ_UU;
+ else
+ uudecode->state = ST_READ_BASE64;
+ }
+ break;
+ case ST_READ_UU:
+ if (total + len * 2 > OUT_BUFF_SIZE)
+ break;
+ body = len - nl;
+ if (!uuchar[*b] || body <= 0) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Insufficient compressed data");
+ return (ARCHIVE_FATAL);
+ }
+ /* Get length of undecoded bytes of curent line. */
+ l = UUDECODE(*b++);
+ body--;
+ if (l > body) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Insufficient compressed data");
+ return (ARCHIVE_FATAL);
+ }
+ if (l == 0) {
+ uudecode->state = ST_UUEND;
+ break;
+ }
+ while (l > 0) {
+ int n = 0;
+
+ if (l > 0) {
+ if (!uuchar[b[0]] || !uuchar[b[1]])
+ break;
+ n = UUDECODE(*b++) << 18;
+ n |= UUDECODE(*b++) << 12;
+ *out++ = n >> 16; total++;
+ --l;
+ }
+ if (l > 0) {
+ if (!uuchar[b[0]])
+ break;
+ n |= UUDECODE(*b++) << 6;
+ *out++ = (n >> 8) & 0xFF; total++;
+ --l;
+ }
+ if (l > 0) {
+ if (!uuchar[b[0]])
+ break;
+ n |= UUDECODE(*b++);
+ *out++ = n & 0xFF; total++;
+ --l;
+ }
+ }
+ if (l) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Insufficient compressed data");
+ return (ARCHIVE_FATAL);
+ }
+ break;
+ case ST_UUEND:
+ if (len - nl == 3 && memcmp(b, "end ", 3) == 0)
+ uudecode->state = ST_FIND_HEAD;
+ else {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Insufficient compressed data");
+ return (ARCHIVE_FATAL);
+ }
+ break;
+ case ST_READ_BASE64:
+ if (total + len * 2 > OUT_BUFF_SIZE)
+ break;
+ l = len - nl;
+ if (l >= 3 && b[0] == '=' && b[1] == '=' &&
+ b[2] == '=') {
+ uudecode->state = ST_FIND_HEAD;
+ break;
+ }
+ while (l > 0) {
+ int n = 0;
+
+ if (l > 0) {
+ if (!base64[b[0]] || !base64[b[1]])
+ break;
+ n = base64num[*b++] << 18;
+ n |= base64num[*b++] << 12;
+ *out++ = n >> 16; total++;
+ l -= 2;
+ }
+ if (l > 0) {
+ if (*b == '=')
+ break;
+ if (!base64[*b])
+ break;
+ n |= base64num[*b++] << 6;
+ *out++ = (n >> 8) & 0xFF; total++;
+ --l;
+ }
+ if (l > 0) {
+ if (*b == '=')
+ break;
+ if (!base64[*b])
+ break;
+ n |= base64num[*b++];
+ *out++ = n & 0xFF; total++;
+ --l;
+ }
+ }
+ if (l && *b != '=') {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Insufficient compressed data");
+ return (ARCHIVE_FATAL);
+ }
+ break;
+ }
+ }
+
+ __archive_read_filter_consume(self->upstream, ravail);
+
+ *buff = uudecode->out_buff;
+ uudecode->total += total;
+ return (total);
+}
+
+static int
+uudecode_filter_close(struct archive_read_filter *self)
+{
+ struct uudecode *uudecode;
+
+ uudecode = (struct uudecode *)self->data;
+ free(uudecode->in_buff);
+ free(uudecode->out_buff);
+ free(uudecode);
+
+ return (ARCHIVE_OK);
+}
+
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_filter_xz.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_filter_xz.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,985 @@
+/*-
+ * Copyright (c) 2009-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2003-2008 Tim Kientzle and Miklos Vajna
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_LZMA_H
+#include <lzma.h>
+#elif HAVE_LZMADEC_H
+#include <lzmadec.h>
+#endif
+
+#include "archive.h"
+#include "archive_endian.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+#if HAVE_LZMA_H && HAVE_LIBLZMA
+
+struct private_data {
+ lzma_stream stream;
+ unsigned char *out_block;
+ size_t out_block_size;
+ int64_t total_out;
+ char eof; /* True = found end of compressed data. */
+ char in_stream;
+
+ /* Following variables are used for lzip only. */
+ char lzip_ver;
+ uint32_t crc32;
+ int64_t member_in;
+ int64_t member_out;
+};
+
+#if LZMA_VERSION_MAJOR >= 5
+/* Effectively disable the limiter. */
+#define LZMA_MEMLIMIT UINT64_MAX
+#else
+/* NOTE: This needs to check memory size which running system has. */
+#define LZMA_MEMLIMIT (1U << 30)
+#endif
+
+/* Combined lzip/lzma/xz filter */
+static ssize_t xz_filter_read(struct archive_read_filter *, const void **);
+static int xz_filter_close(struct archive_read_filter *);
+static int xz_lzma_bidder_init(struct archive_read_filter *);
+
+#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
+
+struct private_data {
+ lzmadec_stream stream;
+ unsigned char *out_block;
+ size_t out_block_size;
+ int64_t total_out;
+ char eof; /* True = found end of compressed data. */
+};
+
+/* Lzma-only filter */
+static ssize_t lzma_filter_read(struct archive_read_filter *, const void **);
+static int lzma_filter_close(struct archive_read_filter *);
+#endif
+
+/*
+ * Note that we can detect xz and lzma compressed files even if we
+ * can't decompress them. (In fact, we like detecting them because we
+ * can give better error messages.) So the bid framework here gets
+ * compiled even if no lzma library is available.
+ */
+static int xz_bidder_bid(struct archive_read_filter_bidder *,
+ struct archive_read_filter *);
+static int xz_bidder_init(struct archive_read_filter *);
+static int lzma_bidder_bid(struct archive_read_filter_bidder *,
+ struct archive_read_filter *);
+static int lzma_bidder_init(struct archive_read_filter *);
+static int lzip_has_member(struct archive_read_filter *);
+static int lzip_bidder_bid(struct archive_read_filter_bidder *,
+ struct archive_read_filter *);
+static int lzip_bidder_init(struct archive_read_filter *);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Deprecated; remove in libarchive 4.0 */
+int
+archive_read_support_compression_xz(struct archive *a)
+{
+ return archive_read_support_filter_xz(a);
+}
+#endif
+
+int
+archive_read_support_filter_xz(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter_bidder *bidder;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_xz");
+
+ if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ bidder->data = NULL;
+ bidder->bid = xz_bidder_bid;
+ bidder->init = xz_bidder_init;
+ bidder->options = NULL;
+ bidder->free = NULL;
+#if HAVE_LZMA_H && HAVE_LIBLZMA
+ return (ARCHIVE_OK);
+#else
+ archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ "Using external unxz program for xz decompression");
+ return (ARCHIVE_WARN);
+#endif
+}
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_read_support_compression_lzma(struct archive *a)
+{
+ return archive_read_support_filter_lzma(a);
+}
+#endif
+
+int
+archive_read_support_filter_lzma(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter_bidder *bidder;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_lzma");
+
+ if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ bidder->data = NULL;
+ bidder->bid = lzma_bidder_bid;
+ bidder->init = lzma_bidder_init;
+ bidder->options = NULL;
+ bidder->free = NULL;
+#if HAVE_LZMA_H && HAVE_LIBLZMA
+ return (ARCHIVE_OK);
+#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
+ return (ARCHIVE_OK);
+#else
+ archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ "Using external unlzma program for lzma decompression");
+ return (ARCHIVE_WARN);
+#endif
+}
+
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_read_support_compression_lzip(struct archive *a)
+{
+ return archive_read_support_filter_lzip(a);
+}
+#endif
+
+int
+archive_read_support_filter_lzip(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter_bidder *bidder;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_lzip");
+
+ if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ bidder->data = NULL;
+ bidder->bid = lzip_bidder_bid;
+ bidder->init = lzip_bidder_init;
+ bidder->options = NULL;
+ bidder->free = NULL;
+#if HAVE_LZMA_H && HAVE_LIBLZMA
+ return (ARCHIVE_OK);
+#else
+ archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ "Using external lzip program for lzip decompression");
+ return (ARCHIVE_WARN);
+#endif
+}
+
+/*
+ * Test whether we can handle this data.
+ */
+static int
+xz_bidder_bid(struct archive_read_filter_bidder *self,
+ struct archive_read_filter *filter)
+{
+ const unsigned char *buffer;
+ ssize_t avail;
+
+ (void)self; /* UNUSED */
+
+ buffer = __archive_read_filter_ahead(filter, 6, &avail);
+ if (buffer == NULL)
+ return (0);
+
+ /*
+ * Verify Header Magic Bytes : FD 37 7A 58 5A 00
+ */
+ if (memcmp(buffer, "\xFD\x37\x7A\x58\x5A\x00", 6) != 0)
+ return (0);
+
+ return (48);
+}
+
+/*
+ * Test whether we can handle this data.
+ *
+ * <sigh> LZMA has a rather poor file signature. Zeros do not
+ * make good signature bytes as a rule, and the only non-zero byte
+ * here is an ASCII character. For example, an uncompressed tar
+ * archive whose first file is ']' would satisfy this check. It may
+ * be necessary to exclude LZMA from compression_all() because of
+ * this. Clients of libarchive would then have to explicitly enable
+ * LZMA checking instead of (or in addition to) compression_all() when
+ * they have other evidence (file name, command-line option) to go on.
+ */
+static int
+lzma_bidder_bid(struct archive_read_filter_bidder *self,
+ struct archive_read_filter *filter)
+{
+ const unsigned char *buffer;
+ ssize_t avail;
+ uint32_t dicsize;
+ uint64_t uncompressed_size;
+ int bits_checked;
+
+ (void)self; /* UNUSED */
+
+ buffer = __archive_read_filter_ahead(filter, 14, &avail);
+ if (buffer == NULL)
+ return (0);
+
+ /* First byte of raw LZMA stream is commonly 0x5d.
+ * The first byte is a special number, which consists of
+ * three parameters of LZMA compression, a number of literal
+ * context bits(which is from 0 to 8, default is 3), a number
+ * of literal pos bits(which is from 0 to 4, default is 0),
+ * a number of pos bits(which is from 0 to 4, default is 2).
+ * The first byte is made by
+ * (pos bits * 5 + literal pos bit) * 9 + * literal contest bit,
+ * and so the default value in this field is
+ * (2 * 5 + 0) * 9 + 3 = 0x5d.
+ * lzma of LZMA SDK has options to change those parameters.
+ * It means a range of this field is from 0 to 224. And lzma of
+ * XZ Utils with option -e records 0x5e in this field. */
+ /* NOTE: If this checking of the first byte increases false
+ * recognition, we should allow only 0x5d and 0x5e for the first
+ * byte of LZMA stream. */
+ bits_checked = 0;
+ if (buffer[0] > (4 * 5 + 4) * 9 + 8)
+ return (0);
+ /* Most likely value in the first byte of LZMA stream. */
+ if (buffer[0] == 0x5d || buffer[0] == 0x5e)
+ bits_checked += 8;
+
+ /* Sixth through fourteenth bytes are uncompressed size,
+ * stored in little-endian order. `-1' means uncompressed
+ * size is unknown and lzma of XZ Utils always records `-1'
+ * in this field. */
+ uncompressed_size = archive_le64dec(buffer+5);
+ if (uncompressed_size == (uint64_t)ARCHIVE_LITERAL_LL(-1))
+ bits_checked += 64;
+
+ /* Second through fifth bytes are dictionary size, stored in
+ * little-endian order. The minimum dictionary size is
+ * 1 << 12(4KiB) which the lzma of LZMA SDK uses with option
+ * -d12 and the maxinam dictionary size is 1 << 27(128MiB)
+ * which the one uses with option -d27.
+ * NOTE: A comment of LZMA SDK source code says this dictionary
+ * range is from 1 << 12 to 1 << 30. */
+ dicsize = archive_le32dec(buffer+1);
+ switch (dicsize) {
+ case 0x00001000:/* lzma of LZMA SDK option -d12. */
+ case 0x00002000:/* lzma of LZMA SDK option -d13. */
+ case 0x00004000:/* lzma of LZMA SDK option -d14. */
+ case 0x00008000:/* lzma of LZMA SDK option -d15. */
+ case 0x00010000:/* lzma of XZ Utils option -0 and -1.
+ * lzma of LZMA SDK option -d16. */
+ case 0x00020000:/* lzma of LZMA SDK option -d17. */
+ case 0x00040000:/* lzma of LZMA SDK option -d18. */
+ case 0x00080000:/* lzma of XZ Utils option -2.
+ * lzma of LZMA SDK option -d19. */
+ case 0x00100000:/* lzma of XZ Utils option -3.
+ * lzma of LZMA SDK option -d20. */
+ case 0x00200000:/* lzma of XZ Utils option -4.
+ * lzma of LZMA SDK option -d21. */
+ case 0x00400000:/* lzma of XZ Utils option -5.
+ * lzma of LZMA SDK option -d22. */
+ case 0x00800000:/* lzma of XZ Utils option -6.
+ * lzma of LZMA SDK option -d23. */
+ case 0x01000000:/* lzma of XZ Utils option -7.
+ * lzma of LZMA SDK option -d24. */
+ case 0x02000000:/* lzma of XZ Utils option -8.
+ * lzma of LZMA SDK option -d25. */
+ case 0x04000000:/* lzma of XZ Utils option -9.
+ * lzma of LZMA SDK option -d26. */
+ case 0x08000000:/* lzma of LZMA SDK option -d27. */
+ bits_checked += 32;
+ break;
+ default:
+ /* If a memory usage for encoding was not enough on
+ * the platform where LZMA stream was made, lzma of
+ * XZ Utils automatically decreased the dictionary
+ * size to enough memory for encoding by 1Mi bytes
+ * (1 << 20).*/
+ if (dicsize <= 0x03F00000 && dicsize >= 0x00300000 &&
+ (dicsize & ((1 << 20)-1)) == 0 &&
+ bits_checked == 8 + 64) {
+ bits_checked += 32;
+ break;
+ }
+ /* Otherwise dictionary size is unlikely. But it is
+ * possible that someone makes lzma stream with
+ * liblzma/LZMA SDK in one's dictionary size. */
+ return (0);
+ }
+
+ /* TODO: The above test is still very weak. It would be
+ * good to do better. */
+
+ return (bits_checked);
+}
+
+static int
+lzip_has_member(struct archive_read_filter *filter)
+{
+ const unsigned char *buffer;
+ ssize_t avail;
+ int bits_checked;
+ int log2dic;
+
+ buffer = __archive_read_filter_ahead(filter, 6, &avail);
+ if (buffer == NULL)
+ return (0);
+
+ /*
+ * Verify Header Magic Bytes : 4C 5A 49 50 (`LZIP')
+ */
+ bits_checked = 0;
+ if (memcmp(buffer, "LZIP", 4) != 0)
+ return (0);
+ bits_checked += 32;
+
+ /* A version number must be 0 or 1 */
+ if (buffer[4] != 0 && buffer[4] != 1)
+ return (0);
+ bits_checked += 8;
+
+ /* Dictionary size. */
+ log2dic = buffer[5] & 0x1f;
+ if (log2dic < 12 || log2dic > 27)
+ return (0);
+ bits_checked += 8;
+
+ return (bits_checked);
+}
+
+static int
+lzip_bidder_bid(struct archive_read_filter_bidder *self,
+ struct archive_read_filter *filter)
+{
+
+ (void)self; /* UNUSED */
+ return (lzip_has_member(filter));
+}
+
+#if HAVE_LZMA_H && HAVE_LIBLZMA
+
+/*
+ * liblzma 4.999.7 and later support both lzma and xz streams.
+ */
+static int
+xz_bidder_init(struct archive_read_filter *self)
+{
+ self->code = ARCHIVE_COMPRESSION_XZ;
+ self->name = "xz";
+ return (xz_lzma_bidder_init(self));
+}
+
+static int
+lzma_bidder_init(struct archive_read_filter *self)
+{
+ self->code = ARCHIVE_COMPRESSION_LZMA;
+ self->name = "lzma";
+ return (xz_lzma_bidder_init(self));
+}
+
+static int
+lzip_bidder_init(struct archive_read_filter *self)
+{
+ self->code = ARCHIVE_COMPRESSION_LZIP;
+ self->name = "lzip";
+ return (xz_lzma_bidder_init(self));
+}
+
+/*
+ * Set an error code and choose an error message
+ */
+static void
+set_error(struct archive_read_filter *self, int ret)
+{
+
+ switch (ret) {
+ case LZMA_STREAM_END: /* Found end of stream. */
+ case LZMA_OK: /* Decompressor made some progress. */
+ break;
+ case LZMA_MEM_ERROR:
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Lzma library error: Cannot allocate memory");
+ break;
+ case LZMA_MEMLIMIT_ERROR:
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Lzma library error: Out of memory");
+ break;
+ case LZMA_FORMAT_ERROR:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Lzma library error: format not recognized");
+ break;
+ case LZMA_OPTIONS_ERROR:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Lzma library error: Invalid options");
+ break;
+ case LZMA_DATA_ERROR:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Lzma library error: Corrupted input data");
+ break;
+ case LZMA_BUF_ERROR:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Lzma library error: No progress is possible");
+ break;
+ default:
+ /* Return an error. */
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Lzma decompression failed: Unknown error");
+ break;
+ }
+}
+
+/*
+ * Setup the callbacks.
+ */
+static int
+xz_lzma_bidder_init(struct archive_read_filter *self)
+{
+ static const size_t out_block_size = 64 * 1024;
+ void *out_block;
+ struct private_data *state;
+ int ret;
+
+ state = (struct private_data *)calloc(sizeof(*state), 1);
+ out_block = (unsigned char *)malloc(out_block_size);
+ if (state == NULL || out_block == NULL) {
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate data for xz decompression");
+ free(out_block);
+ free(state);
+ return (ARCHIVE_FATAL);
+ }
+
+ self->data = state;
+ state->out_block_size = out_block_size;
+ state->out_block = out_block;
+ self->read = xz_filter_read;
+ self->skip = NULL; /* not supported */
+ self->close = xz_filter_close;
+
+ state->stream.avail_in = 0;
+
+ state->stream.next_out = state->out_block;
+ state->stream.avail_out = state->out_block_size;
+
+ state->crc32 = 0;
+ if (self->code == ARCHIVE_COMPRESSION_LZIP) {
+ /*
+ * We have to read a lzip header and use it to initialize
+ * compression library, thus we cannot initialize the
+ * library for lzip here.
+ */
+ state->in_stream = 0;
+ return (ARCHIVE_OK);
+ } else
+ state->in_stream = 1;
+
+ /* Initialize compression library. */
+ if (self->code == ARCHIVE_COMPRESSION_XZ)
+ ret = lzma_stream_decoder(&(state->stream),
+ LZMA_MEMLIMIT,/* memlimit */
+ LZMA_CONCATENATED);
+ else
+ ret = lzma_alone_decoder(&(state->stream),
+ LZMA_MEMLIMIT);/* memlimit */
+
+ if (ret == LZMA_OK)
+ return (ARCHIVE_OK);
+
+ /* Library setup failed: Choose an error message and clean up. */
+ set_error(self, ret);
+
+ free(state->out_block);
+ free(state);
+ self->data = NULL;
+ return (ARCHIVE_FATAL);
+}
+
+static int
+lzip_init(struct archive_read_filter *self)
+{
+ struct private_data *state;
+ const unsigned char *h;
+ lzma_filter filters[2];
+ unsigned char props[5];
+ ssize_t avail_in;
+ uint32_t dicsize;
+ int log2dic, ret;
+
+ state = (struct private_data *)self->data;
+ h = __archive_read_filter_ahead(self->upstream, 6, &avail_in);
+ if (h == NULL)
+ return (ARCHIVE_FATAL);
+
+ /* Get a version number. */
+ state->lzip_ver = h[4];
+
+ /*
+ * Setup lzma property.
+ */
+ props[0] = 0x5d;
+
+ /* Get dictionary size. */
+ log2dic = h[5] & 0x1f;
+ if (log2dic < 12 || log2dic > 27)
+ return (ARCHIVE_FATAL);
+ dicsize = 1U << log2dic;
+ if (log2dic > 12)
+ dicsize -= (dicsize / 16) * (h[5] >> 5);
+ archive_le32enc(props+1, dicsize);
+
+ /* Consume lzip header. */
+ __archive_read_filter_consume(self->upstream, 6);
+ state->member_in = 6;
+
+ filters[0].id = LZMA_FILTER_LZMA1;
+ filters[0].options = NULL;
+ filters[1].id = LZMA_VLI_UNKNOWN;
+ filters[1].options = NULL;
+
+ ret = lzma_properties_decode(&filters[0], NULL, props, sizeof(props));
+ if (ret != LZMA_OK) {
+ set_error(self, ret);
+ return (ARCHIVE_FATAL);
+ }
+ ret = lzma_raw_decoder(&(state->stream), filters);
+#if LZMA_VERSION < 50000030
+ free(filters[0].options);
+#endif
+ if (ret != LZMA_OK) {
+ set_error(self, ret);
+ return (ARCHIVE_FATAL);
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+lzip_tail(struct archive_read_filter *self)
+{
+ struct private_data *state;
+ const unsigned char *f;
+ ssize_t avail_in;
+ int tail;
+
+ state = (struct private_data *)self->data;
+ if (state->lzip_ver == 0)
+ tail = 12;
+ else
+ tail = 20;
+ f = __archive_read_filter_ahead(self->upstream, tail, &avail_in);
+ if (f == NULL && avail_in < 0)
+ return (ARCHIVE_FATAL);
+ if (avail_in < tail) {
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "Lzip: Remaining data is less bytes");
+ return (ARCHIVE_FAILED);
+ }
+
+ /* Check the crc32 value of the uncompressed data of the current
+ * member */
+ if (state->crc32 != archive_le32dec(f)) {
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "Lzip: CRC32 error");
+ return (ARCHIVE_FAILED);
+ }
+
+ /* Check the uncompressed size of the current member */
+ if ((uint64_t)state->member_out != archive_le64dec(f + 4)) {
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "Lzip: Uncompressed size error");
+ return (ARCHIVE_FAILED);
+ }
+
+ /* Check the total size of the current member */
+ if (state->lzip_ver == 1 &&
+ (uint64_t)state->member_in + tail != archive_le64dec(f + 12)) {
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "Lzip: Member size error");
+ return (ARCHIVE_FAILED);
+ }
+ __archive_read_filter_consume(self->upstream, tail);
+
+ /* If current lzip data consists of multi member, try decompressing
+ * a next member. */
+ if (lzip_has_member(self->upstream) != 0) {
+ state->in_stream = 0;
+ state->crc32 = 0;
+ state->member_out = 0;
+ state->member_in = 0;
+ state->eof = 0;
+ }
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Return the next block of decompressed data.
+ */
+static ssize_t
+xz_filter_read(struct archive_read_filter *self, const void **p)
+{
+ struct private_data *state;
+ size_t decompressed;
+ ssize_t avail_in;
+ int ret;
+
+ state = (struct private_data *)self->data;
+
+ /* Empty our output buffer. */
+ state->stream.next_out = state->out_block;
+ state->stream.avail_out = state->out_block_size;
+
+ /* Try to fill the output buffer. */
+ while (state->stream.avail_out > 0 && !state->eof) {
+ if (!state->in_stream) {
+ /*
+ * Initialize liblzma for lzip
+ */
+ ret = lzip_init(self);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ state->in_stream = 1;
+ }
+ state->stream.next_in =
+ __archive_read_filter_ahead(self->upstream, 1, &avail_in);
+ if (state->stream.next_in == NULL && avail_in < 0) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "truncated input");
+ return (ARCHIVE_FATAL);
+ }
+ state->stream.avail_in = avail_in;
+
+ /* Decompress as much as we can in one pass. */
+ ret = lzma_code(&(state->stream),
+ (state->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN);
+ switch (ret) {
+ case LZMA_STREAM_END: /* Found end of stream. */
+ state->eof = 1;
+ /* FALL THROUGH */
+ case LZMA_OK: /* Decompressor made some progress. */
+ __archive_read_filter_consume(self->upstream,
+ avail_in - state->stream.avail_in);
+ state->member_in +=
+ avail_in - state->stream.avail_in;
+ break;
+ default:
+ set_error(self, ret);
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ decompressed = state->stream.next_out - state->out_block;
+ state->total_out += decompressed;
+ state->member_out += decompressed;
+ if (decompressed == 0)
+ *p = NULL;
+ else {
+ *p = state->out_block;
+ if (self->code == ARCHIVE_COMPRESSION_LZIP) {
+ state->crc32 = lzma_crc32(state->out_block,
+ decompressed, state->crc32);
+ if (state->eof) {
+ ret = lzip_tail(self);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+ }
+ }
+ return (decompressed);
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+xz_filter_close(struct archive_read_filter *self)
+{
+ struct private_data *state;
+
+ state = (struct private_data *)self->data;
+ lzma_end(&(state->stream));
+ free(state->out_block);
+ free(state);
+ return (ARCHIVE_OK);
+}
+
+#else
+
+#if HAVE_LZMADEC_H && HAVE_LIBLZMADEC
+
+/*
+ * If we have the older liblzmadec library, then we can handle
+ * LZMA streams but not XZ streams.
+ */
+
+/*
+ * Setup the callbacks.
+ */
+static int
+lzma_bidder_init(struct archive_read_filter *self)
+{
+ static const size_t out_block_size = 64 * 1024;
+ void *out_block;
+ struct private_data *state;
+ ssize_t ret, avail_in;
+
+ self->code = ARCHIVE_COMPRESSION_LZMA;
+ self->name = "lzma";
+
+ state = (struct private_data *)calloc(sizeof(*state), 1);
+ out_block = (unsigned char *)malloc(out_block_size);
+ if (state == NULL || out_block == NULL) {
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate data for lzma decompression");
+ free(out_block);
+ free(state);
+ return (ARCHIVE_FATAL);
+ }
+
+ self->data = state;
+ state->out_block_size = out_block_size;
+ state->out_block = out_block;
+ self->read = lzma_filter_read;
+ self->skip = NULL; /* not supported */
+ self->close = lzma_filter_close;
+
+ /* Prime the lzma library with 18 bytes of input. */
+ state->stream.next_in = (unsigned char *)(uintptr_t)
+ __archive_read_filter_ahead(self->upstream, 18, &avail_in);
+ if (state->stream.next_in == NULL)
+ return (ARCHIVE_FATAL);
+ state->stream.avail_in = avail_in;
+ state->stream.next_out = state->out_block;
+ state->stream.avail_out = state->out_block_size;
+
+ /* Initialize compression library. */
+ ret = lzmadec_init(&(state->stream));
+ __archive_read_filter_consume(self->upstream,
+ avail_in - state->stream.avail_in);
+ if (ret == LZMADEC_OK)
+ return (ARCHIVE_OK);
+
+ /* Library setup failed: Clean up. */
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing lzma library");
+
+ /* Override the error message if we know what really went wrong. */
+ switch (ret) {
+ case LZMADEC_HEADER_ERROR:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "invalid header");
+ break;
+ case LZMADEC_MEM_ERROR:
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Internal error initializing compression library: "
+ "out of memory");
+ break;
+ }
+
+ free(state->out_block);
+ free(state);
+ self->data = NULL;
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Return the next block of decompressed data.
+ */
+static ssize_t
+lzma_filter_read(struct archive_read_filter *self, const void **p)
+{
+ struct private_data *state;
+ size_t decompressed;
+ ssize_t avail_in, ret;
+
+ state = (struct private_data *)self->data;
+
+ /* Empty our output buffer. */
+ state->stream.next_out = state->out_block;
+ state->stream.avail_out = state->out_block_size;
+
+ /* Try to fill the output buffer. */
+ while (state->stream.avail_out > 0 && !state->eof) {
+ state->stream.next_in = (unsigned char *)(uintptr_t)
+ __archive_read_filter_ahead(self->upstream, 1, &avail_in);
+ if (state->stream.next_in == NULL && avail_in < 0) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "truncated lzma input");
+ return (ARCHIVE_FATAL);
+ }
+ state->stream.avail_in = avail_in;
+
+ /* Decompress as much as we can in one pass. */
+ ret = lzmadec_decode(&(state->stream), avail_in == 0);
+ switch (ret) {
+ case LZMADEC_STREAM_END: /* Found end of stream. */
+ state->eof = 1;
+ /* FALL THROUGH */
+ case LZMADEC_OK: /* Decompressor made some progress. */
+ __archive_read_filter_consume(self->upstream,
+ avail_in - state->stream.avail_in);
+ break;
+ case LZMADEC_BUF_ERROR: /* Insufficient input data? */
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Insufficient compressed data");
+ return (ARCHIVE_FATAL);
+ default:
+ /* Return an error. */
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Lzma decompression failed");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ decompressed = state->stream.next_out - state->out_block;
+ state->total_out += decompressed;
+ if (decompressed == 0)
+ *p = NULL;
+ else
+ *p = state->out_block;
+ return (decompressed);
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+lzma_filter_close(struct archive_read_filter *self)
+{
+ struct private_data *state;
+ int ret;
+
+ state = (struct private_data *)self->data;
+ ret = ARCHIVE_OK;
+ switch (lzmadec_end(&(state->stream))) {
+ case LZMADEC_OK:
+ break;
+ default:
+ archive_set_error(&(self->archive->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up %s compressor",
+ self->archive->archive.compression_name);
+ ret = ARCHIVE_FATAL;
+ }
+
+ free(state->out_block);
+ free(state);
+ return (ret);
+}
+
+#else
+
+/*
+ *
+ * If we have no suitable library on this system, we can't actually do
+ * the decompression. We can, however, still detect compressed
+ * archives and emit a useful message.
+ *
+ */
+static int
+lzma_bidder_init(struct archive_read_filter *self)
+{
+ int r;
+
+ r = __archive_read_program(self, "unlzma");
+ /* Note: We set the format here even if __archive_read_program()
+ * above fails. We do, after all, know what the format is
+ * even if we weren't able to read it. */
+ self->code = ARCHIVE_COMPRESSION_LZMA;
+ self->name = "lzma";
+ return (r);
+}
+
+#endif /* HAVE_LZMADEC_H */
+
+
+static int
+xz_bidder_init(struct archive_read_filter *self)
+{
+ int r;
+
+ r = __archive_read_program(self, "unxz");
+ /* Note: We set the format here even if __archive_read_program()
+ * above fails. We do, after all, know what the format is
+ * even if we weren't able to read it. */
+ self->code = ARCHIVE_COMPRESSION_XZ;
+ self->name = "xz";
+ return (r);
+}
+
+static int
+lzip_bidder_init(struct archive_read_filter *self)
+{
+ int r;
+
+ r = __archive_read_program(self, "unlzip");
+ /* Note: We set the format here even if __archive_read_program()
+ * above fails. We do, after all, know what the format is
+ * even if we weren't able to read it. */
+ self->code = ARCHIVE_COMPRESSION_LZIP;
+ self->name = "lzip";
+ return (r);
+}
+
+
+#endif /* HAVE_LZMA_H */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_format_7zip.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,3706 @@
+/*-
+ * Copyright (c) 2011 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_BZLIB_H
+#include <bzlib.h>
+#endif
+#ifdef HAVE_LZMA_H
+#include <lzma.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_entry_locale.h"
+#include "archive_ppmd7_private.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+#include "archive_endian.h"
+
+#ifndef HAVE_ZLIB_H
+#include "archive_crc32.h"
+#endif
+
+#define _7ZIP_SIGNATURE "7z\xBC\xAF\x27\x1C"
+#define SFX_MIN_ADDR 0x27000
+#define SFX_MAX_ADDR 0x60000
+
+
+/*
+ * Codec ID
+ */
+#define _7Z_COPY 0
+#define _7Z_LZMA 0x030101
+#define _7Z_LZMA2 0x21
+#define _7Z_DEFLATE 0x040108
+#define _7Z_BZ2 0x040202
+#define _7Z_PPMD 0x030401
+#define _7Z_DELTA 0x03
+#define _7Z_CRYPTO 0x06F10701
+#define _7Z_X86 0x03030103
+#define _7Z_X86_BCJ2 0x0303011B
+#define _7Z_POWERPC 0x03030205
+#define _7Z_IA64 0x03030401
+#define _7Z_ARM 0x03030501
+#define _7Z_ARMTHUMB 0x03030701
+#define _7Z_SPARC 0x03030805
+
+/*
+ * 7-Zip header property IDs.
+ */
+#define kEnd 0x00
+#define kHeader 0x01
+#define kArchiveProperties 0x02
+#define kAdditionalStreamsInfo 0x03
+#define kMainStreamsInfo 0x04
+#define kFilesInfo 0x05
+#define kPackInfo 0x06
+#define kUnPackInfo 0x07
+#define kSubStreamsInfo 0x08
+#define kSize 0x09
+#define kCRC 0x0A
+#define kFolder 0x0B
+#define kCodersUnPackSize 0x0C
+#define kNumUnPackStream 0x0D
+#define kEmptyStream 0x0E
+#define kEmptyFile 0x0F
+#define kAnti 0x10
+#define kName 0x11
+#define kCTime 0x12
+#define kATime 0x13
+#define kMTime 0x14
+#define kAttributes 0x15
+#define kEncodedHeader 0x17
+
+struct _7z_digests {
+ unsigned char *defineds;
+ uint32_t *digests;
+};
+
+
+struct _7z_folder {
+ uint64_t numCoders;
+ struct _7z_coder {
+ unsigned long codec;
+ uint64_t numInStreams;
+ uint64_t numOutStreams;
+ uint64_t propertiesSize;
+ unsigned char *properties;
+ } *coders;
+ uint64_t numBindPairs;
+ struct {
+ uint64_t inIndex;
+ uint64_t outIndex;
+ } *bindPairs;
+ uint64_t numPackedStreams;
+ uint64_t *packedStreams;
+ uint64_t numInStreams;
+ uint64_t numOutStreams;
+ uint64_t *unPackSize;
+ unsigned char digest_defined;
+ uint32_t digest;
+ uint64_t numUnpackStreams;
+ uint32_t packIndex;
+ /* Unoperated bytes. */
+ uint64_t skipped_bytes;
+};
+
+struct _7z_coders_info {
+ uint64_t numFolders;
+ struct _7z_folder *folders;
+ uint64_t dataStreamIndex;
+};
+
+struct _7z_pack_info {
+ uint64_t pos;
+ uint64_t numPackStreams;
+ uint64_t *sizes;
+ struct _7z_digests digest;
+ /* Calculated from pos and numPackStreams. */
+ uint64_t *positions;
+};
+
+struct _7z_substream_info {
+ size_t unpack_streams;
+ uint64_t *unpackSizes;
+ unsigned char *digestsDefined;
+ uint32_t *digests;
+};
+
+struct _7z_stream_info {
+ struct _7z_pack_info pi;
+ struct _7z_coders_info ci;
+ struct _7z_substream_info ss;
+};
+
+struct _7z_header_info {
+ uint64_t dataIndex;
+
+ unsigned char *emptyStreamBools;
+ unsigned char *emptyFileBools;
+ unsigned char *antiBools;
+ unsigned char *attrBools;
+};
+
+struct _7zip_entry {
+ size_t name_len;
+ unsigned char *utf16name;
+#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
+ const wchar_t *wname;
+#endif
+ uint32_t folderIndex;
+ uint32_t ssIndex;
+ unsigned flg;
+#define MTIME_IS_SET (1<<0)
+#define ATIME_IS_SET (1<<1)
+#define CTIME_IS_SET (1<<2)
+#define CRC32_IS_SET (1<<3)
+#define HAS_STREAM (1<<4)
+
+ time_t mtime;
+ time_t atime;
+ time_t ctime;
+ long mtime_ns;
+ long atime_ns;
+ long ctime_ns;
+ uint32_t mode;
+ uint32_t attr;
+};
+
+struct _7zip {
+ /* Structural information about the archive. */
+ struct _7z_stream_info si;
+
+ int header_is_being_read;
+ int header_is_encoded;
+ uint64_t header_bytes_remaining;
+ unsigned long header_crc32;
+ /* Header offset to check that reading pointes of the file contens
+ * will not exceed the header. */
+ uint64_t header_offset;
+ /* Base offset of the archive file for a seek in case reading SFX. */
+ uint64_t seek_base;
+
+ /* List of entries */
+ size_t entries_remaining;
+ uint64_t numFiles;
+ struct _7zip_entry *entries;
+ struct _7zip_entry *entry;
+ unsigned char *entry_names;
+
+ /* entry_bytes_remaining is the number of bytes we expect. */
+ int64_t entry_offset;
+ uint64_t entry_bytes_remaining;
+
+ /* Running CRC32 of the decompressed data */
+ unsigned long entry_crc32;
+
+ /* Flags to mark progress of decompression. */
+ char end_of_entry;
+
+ /* Uncompressed buffer control. */
+#define UBUFF_SIZE (64 * 1024)
+ unsigned char *uncompressed_buffer;
+ unsigned char *uncompressed_buffer_pointer;
+ size_t uncompressed_buffer_size;
+ size_t uncompressed_buffer_bytes_remaining;
+
+ /* Offset of the compressed data. */
+ int64_t stream_offset;
+
+ /*
+ * Decompressing control data.
+ */
+ unsigned folder_index;
+ uint64_t folder_outbytes_remaining;
+ unsigned pack_stream_index;
+ unsigned pack_stream_remaining;
+ uint64_t pack_stream_inbytes_remaining;
+ size_t pack_stream_bytes_unconsumed;
+
+ /* The codec information of a folder. */
+ unsigned long codec;
+ unsigned long codec2;
+
+ /*
+ * Decompressor controllers.
+ */
+ /* Decording LZMA1 and LZMA2 data. */
+#ifdef HAVE_LZMA_H
+ lzma_stream lzstream;
+ int lzstream_valid;
+#endif
+ /* Decording bzip2 data. */
+#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
+ bz_stream bzstream;
+ int bzstream_valid;
+#endif
+ /* Decording deflate data. */
+#ifdef HAVE_ZLIB_H
+ z_stream stream;
+ int stream_valid;
+#endif
+ /* Decording PPMd data. */
+ int ppmd7_stat;
+ CPpmd7 ppmd7_context;
+ CPpmd7z_RangeDec range_dec;
+ IByteIn bytein;
+ struct {
+ const unsigned char *next_in;
+ int64_t avail_in;
+ int64_t total_in;
+ unsigned char *next_out;
+ int64_t avail_out;
+ int64_t total_out;
+ int overconsumed;
+ } ppstream;
+ int ppmd7_valid;
+
+ /* Decoding BCJ and BCJ2 data. */
+ uint32_t bcj_state;
+ size_t odd_bcj_size;
+ unsigned char odd_bcj[4];
+ /* Decoding BCJ data. */
+ size_t bcj_prevPosT;
+ uint32_t bcj_prevMask;
+ uint32_t bcj_ip;
+
+ /* Decoding BCJ2 data. */
+ size_t main_stream_bytes_remaining;
+ unsigned char *sub_stream_buff[3];
+ size_t sub_stream_size[3];
+ size_t sub_stream_bytes_remaining[3];
+ unsigned char *tmp_stream_buff;
+ size_t tmp_stream_buff_size;
+ size_t tmp_stream_bytes_avail;
+ size_t tmp_stream_bytes_remaining;
+#ifdef _LZMA_PROB32
+#define CProb uint32_t
+#else
+#define CProb uint16_t
+#endif
+ CProb bcj2_p[256 + 2];
+ uint8_t bcj2_prevByte;
+ uint32_t bcj2_range;
+ uint32_t bcj2_code;
+ uint64_t bcj2_outPos;
+
+ /* Filename character-set conversion data. */
+ struct archive_string_conv *sconv;
+
+ char format_name[64];
+};
+
+static int archive_read_format_7zip_bid(struct archive_read *, int);
+static int archive_read_format_7zip_cleanup(struct archive_read *);
+static int archive_read_format_7zip_read_data(struct archive_read *,
+ const void **, size_t *, int64_t *);
+static int archive_read_format_7zip_read_data_skip(struct archive_read *);
+static int archive_read_format_7zip_read_header(struct archive_read *,
+ struct archive_entry *);
+static int check_7zip_header_in_sfx(const char *);
+static unsigned long decode_codec_id(const unsigned char *, size_t);
+static int decode_encoded_header_info(struct archive_read *,
+ struct _7z_stream_info *);
+static int decompress(struct archive_read *, struct _7zip *,
+ void *, size_t *, const void *, size_t *);
+static ssize_t extract_pack_stream(struct archive_read *, size_t);
+static void fileTimeToUtc(uint64_t, time_t *, long *);
+static uint64_t folder_uncompressed_size(struct _7z_folder *);
+static void free_CodersInfo(struct _7z_coders_info *);
+static void free_Digest(struct _7z_digests *);
+static void free_Folder(struct _7z_folder *);
+static void free_Header(struct _7z_header_info *);
+static void free_PackInfo(struct _7z_pack_info *);
+static void free_StreamsInfo(struct _7z_stream_info *);
+static void free_SubStreamsInfo(struct _7z_substream_info *);
+static int free_decompression(struct archive_read *, struct _7zip *);
+static ssize_t get_uncompressed_data(struct archive_read *, const void **,
+ size_t, size_t);
+static const unsigned char * header_bytes(struct archive_read *, size_t);
+static int init_decompression(struct archive_read *, struct _7zip *,
+ const struct _7z_coder *, const struct _7z_coder *);
+static int parse_7zip_uint64(struct archive_read *, uint64_t *);
+static int read_Bools(struct archive_read *, unsigned char *, size_t);
+static int read_CodersInfo(struct archive_read *,
+ struct _7z_coders_info *);
+static int read_Digests(struct archive_read *, struct _7z_digests *,
+ size_t);
+static int read_Folder(struct archive_read *, struct _7z_folder *);
+static int read_Header(struct archive_read *, struct _7z_header_info *,
+ int);
+static int read_PackInfo(struct archive_read *, struct _7z_pack_info *);
+static int read_StreamsInfo(struct archive_read *,
+ struct _7z_stream_info *);
+static int read_SubStreamsInfo(struct archive_read *,
+ struct _7z_substream_info *, struct _7z_folder *, size_t);
+static int read_Times(struct archive_read *, struct _7z_header_info *,
+ int);
+static void read_consume(struct archive_read *);
+static ssize_t read_stream(struct archive_read *, const void **, size_t,
+ size_t);
+static int seek_pack(struct archive_read *);
+static int64_t skip_stream(struct archive_read *, size_t);
+static int skip_sfx(struct archive_read *, ssize_t);
+static int slurp_central_directory(struct archive_read *, struct _7zip *,
+ struct _7z_header_info *);
+static int setup_decode_folder(struct archive_read *, struct _7z_folder *,
+ int);
+static void x86_Init(struct _7zip *);
+static size_t x86_Convert(struct _7zip *, uint8_t *, size_t);
+static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
+
+
+int
+archive_read_support_format_7zip(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct _7zip *zip;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_format_7zip");
+
+ zip = calloc(1, sizeof(*zip));
+ if (zip == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate 7zip data");
+ return (ARCHIVE_FATAL);
+ }
+
+ r = __archive_read_register_format(a,
+ zip,
+ "7zip",
+ archive_read_format_7zip_bid,
+ NULL,
+ archive_read_format_7zip_read_header,
+ archive_read_format_7zip_read_data,
+ archive_read_format_7zip_read_data_skip,
+ archive_read_format_7zip_cleanup);
+
+ if (r != ARCHIVE_OK)
+ free(zip);
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_7zip_bid(struct archive_read *a, int best_bid)
+{
+ const char *p;
+
+ /* If someone has already bid more than 32, then avoid
+ trashing the look-ahead buffers with a seek. */
+ if (best_bid > 32)
+ return (-1);
+
+ if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
+ return (0);
+
+ /* If first six bytes are the 7-Zip signature,
+ * return the bid right now. */
+ if (memcmp(p, _7ZIP_SIGNATURE, 6) == 0)
+ return (48);
+
+ /*
+ * It may a 7-Zip SFX archive file. If first two bytes are
+ * 'M' and 'Z' available on Windows or first four bytes are
+ * "\x7F\x45LF" available on posix like system, seek the 7-Zip
+ * signature. Although we will perform a seek when reading
+ * a header, what we do not use __archive_read_seek() here is
+ * due to a bidding performance.
+ */
+ if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
+ ssize_t offset = SFX_MIN_ADDR;
+ ssize_t window = 4096;
+ ssize_t bytes_avail;
+ while (offset + window <= (SFX_MAX_ADDR)) {
+ const char *buff = __archive_read_ahead(a,
+ offset + window, &bytes_avail);
+ if (buff == NULL) {
+ /* Remaining bytes are less than window. */
+ window >>= 1;
+ if (window < 0x40)
+ return (0);
+ continue;
+ }
+ p = buff + offset;
+ while (p + 32 < buff + bytes_avail) {
+ int step = check_7zip_header_in_sfx(p);
+ if (step == 0)
+ return (48);
+ p += step;
+ }
+ offset = p - buff;
+ }
+ }
+ return (0);
+}
+
+static int
+check_7zip_header_in_sfx(const char *p)
+{
+ switch ((unsigned char)p[5]) {
+ case 0x1C:
+ if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0)
+ return (6);
+ /*
+ * Test the CRC because its extraction code has 7-Zip
+ * Magic Code, so we should do this in order not to
+ * make a mis-detection.
+ */
+ if (crc32(0, (const unsigned char *)p + 12, 20)
+ != archive_le32dec(p + 8))
+ return (6);
+ /* Hit the header! */
+ return (0);
+ case 0x37: return (5);
+ case 0x7A: return (4);
+ case 0xBC: return (3);
+ case 0xAF: return (2);
+ case 0x27: return (1);
+ default: return (6);
+ }
+}
+
+static int
+skip_sfx(struct archive_read *a, ssize_t bytes_avail)
+{
+ const void *h;
+ const char *p, *q;
+ size_t skip, offset;
+ ssize_t bytes, window;
+
+ /*
+ * If bytes_avail > SFX_MIN_ADDR we do not have to call
+ * __archive_read_seek() at this time since we have
+ * alredy had enough data.
+ */
+ if (bytes_avail > SFX_MIN_ADDR)
+ __archive_read_consume(a, SFX_MIN_ADDR);
+ else if (__archive_read_seek(a, SFX_MIN_ADDR, SEEK_SET) < 0)
+ return (ARCHIVE_FATAL);
+
+ offset = 0;
+ window = 1;
+ while (offset + window <= SFX_MAX_ADDR - SFX_MIN_ADDR) {
+ h = __archive_read_ahead(a, window, &bytes);
+ if (h == NULL) {
+ /* Remaining bytes are less than window. */
+ window >>= 1;
+ if (window < 0x40)
+ goto fatal;
+ continue;
+ }
+ if (bytes < 6) {
+ /* This case might happen when window == 1. */
+ window = 4096;
+ continue;
+ }
+ p = (const char *)h;
+ q = p + bytes;
+
+ /*
+ * Scan ahead until we find something that looks
+ * like the 7-Zip header.
+ */
+ while (p + 32 < q) {
+ int step = check_7zip_header_in_sfx(p);
+ if (step == 0) {
+ struct _7zip *zip =
+ (struct _7zip *)a->format->data;
+ skip = p - (const char *)h;
+ __archive_read_consume(a, skip);
+ zip->seek_base = SFX_MIN_ADDR + offset + skip;
+ return (ARCHIVE_OK);
+ }
+ p += step;
+ }
+ skip = p - (const char *)h;
+ __archive_read_consume(a, skip);
+ offset += skip;
+ if (window == 1)
+ window = 4096;
+ }
+fatal:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Couldn't find out 7-Zip header");
+ return (ARCHIVE_FATAL);
+}
+
+static int
+archive_read_format_7zip_read_header(struct archive_read *a,
+ struct archive_entry *entry)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ struct _7zip_entry *zip_entry;
+ int r, ret = ARCHIVE_OK;
+
+ a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
+ if (a->archive.archive_format_name == NULL)
+ a->archive.archive_format_name = "7-Zip";
+
+ if (zip->entries == NULL) {
+ struct _7z_header_info header;
+
+ memset(&header, 0, sizeof(header));
+ r = slurp_central_directory(a, zip, &header);
+ free_Header(&header);
+ if (r != ARCHIVE_OK)
+ return (r);
+ zip->entries_remaining = zip->numFiles;
+ zip->entry = zip->entries;
+ } else {
+ ++zip->entry;
+ }
+ zip_entry = zip->entry;
+
+ if (zip->entries_remaining <= 0)
+ return ARCHIVE_EOF;
+ --zip->entries_remaining;
+
+ zip->entry_offset = 0;
+ zip->end_of_entry = 0;
+ zip->entry_crc32 = crc32(0, NULL, 0);
+
+ /* Setup a string conversion for a filename. */
+ if (zip->sconv == NULL) {
+ zip->sconv = archive_string_conversion_from_charset(
+ &a->archive, "UTF-16LE", 1);
+ if (zip->sconv == NULL)
+ return (ARCHIVE_FATAL);
+ }
+
+ if (archive_entry_copy_pathname_l(entry,
+ (const char *)zip_entry->utf16name,
+ zip_entry->name_len, zip->sconv) != 0) {
+ if (errno == ENOMEM) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for Pathname");
+ return (ARCHIVE_FATAL);
+ }
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Pathname cannot be converted "
+ "from %s to current locale.",
+ archive_string_conversion_charset_name(zip->sconv));
+ ret = ARCHIVE_WARN;
+ }
+
+ /* Populate some additional entry fields: */
+ archive_entry_set_mode(entry, zip_entry->mode);
+ if (zip_entry->flg & MTIME_IS_SET)
+ archive_entry_set_mtime(entry, zip_entry->mtime,
+ zip_entry->mtime_ns);
+ if (zip_entry->flg & CTIME_IS_SET)
+ archive_entry_set_ctime(entry, zip_entry->ctime,
+ zip_entry->ctime_ns);
+ if (zip_entry->flg & ATIME_IS_SET)
+ archive_entry_set_atime(entry, zip_entry->atime,
+ zip_entry->atime_ns);
+ if (zip_entry->ssIndex != (uint32_t)-1) {
+ zip->entry_bytes_remaining =
+ zip->si.ss.unpackSizes[zip_entry->ssIndex];
+ archive_entry_set_size(entry, zip->entry_bytes_remaining);
+ } else {
+ zip->entry_bytes_remaining = 0;
+ archive_entry_set_size(entry, 0);
+ }
+
+ /* If there's no body, force read_data() to return EOF immediately. */
+ if (zip->entry_bytes_remaining < 1)
+ zip->end_of_entry = 1;
+
+ if ((zip_entry->mode & AE_IFMT) == AE_IFLNK) {
+ unsigned char *symname = NULL;
+ size_t symsize = 0;
+
+ /*
+ * Symbolic-name is recorded as its contents. We have to
+ * read the contents at this time.
+ */
+ while (zip->entry_bytes_remaining > 0) {
+ const void *buff;
+ size_t size;
+ int64_t offset;
+
+ r = archive_read_format_7zip_read_data(a, &buff,
+ &size, &offset);
+ if (r < ARCHIVE_WARN)
+ return (r);
+ symname = realloc(symname, symsize + size + 1);
+ if (symname == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for Symname");
+ return (ARCHIVE_FATAL);
+ }
+ memcpy(symname+symsize, buff, size);
+ symsize += size;
+ }
+ if (symsize == 0) {
+ /* If there is no synname, handle it as a regular
+ * file. */
+ zip_entry->mode &= ~AE_IFMT;
+ zip_entry->mode |= AE_IFREG;
+ archive_entry_set_mode(entry, zip_entry->mode);
+ } else {
+ symname[symsize] = '\0';
+ archive_entry_copy_symlink(entry,
+ (const char *)symname);
+ free(symname);
+ }
+ archive_entry_set_size(entry, 0);
+ }
+
+ /* Set up a more descriptive format name. */
+ sprintf(zip->format_name, "7-Zip");
+ a->archive.archive_format_name = zip->format_name;
+
+ return (ret);
+}
+
+static int
+archive_read_format_7zip_read_data(struct archive_read *a,
+ const void **buff, size_t *size, int64_t *offset)
+{
+ struct _7zip *zip;
+ ssize_t bytes;
+ int ret = ARCHIVE_OK;
+
+ zip = (struct _7zip *)(a->format->data);
+
+ if (zip->pack_stream_bytes_unconsumed)
+ read_consume(a);
+
+ /*
+ * If we hit end-of-entry last time, clean up and return
+ * ARCHIVE_EOF this time.
+ */
+ if (zip->end_of_entry) {
+ *offset = zip->entry_offset;
+ *size = 0;
+ *buff = NULL;
+ return (ARCHIVE_EOF);
+ }
+
+ bytes = read_stream(a, buff, zip->entry_bytes_remaining, 0);
+ if (bytes < 0)
+ return ((int)bytes);
+ if (bytes == 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated 7-Zip file body");
+ return (ARCHIVE_FATAL);
+ }
+ zip->entry_bytes_remaining -= bytes;
+ if (zip->entry_bytes_remaining == 0)
+ zip->end_of_entry = 1;
+
+ /* Update checksum */
+ if ((zip->entry->flg & CRC32_IS_SET) && bytes)
+ zip->entry_crc32 = crc32(zip->entry_crc32, *buff, bytes);
+
+ /* If we hit the end, swallow any end-of-data marker. */
+ if (zip->end_of_entry) {
+ /* Check computed CRC against file contents. */
+ if ((zip->entry->flg & CRC32_IS_SET) &&
+ zip->si.ss.digests[zip->entry->ssIndex] !=
+ zip->entry_crc32) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "7-Zip bad CRC: 0x%lx should be 0x%lx",
+ (unsigned long)zip->entry_crc32,
+ (unsigned long)zip->si.ss.digests[
+ zip->entry->ssIndex]);
+ ret = ARCHIVE_WARN;
+ }
+ }
+
+ *size = bytes;
+ *offset = zip->entry_offset;
+ zip->entry_offset += bytes;
+
+ return (ret);
+}
+
+static int
+archive_read_format_7zip_read_data_skip(struct archive_read *a)
+{
+ struct _7zip *zip;
+ int64_t bytes_skipped;
+
+ zip = (struct _7zip *)(a->format->data);
+
+ if (zip->pack_stream_bytes_unconsumed)
+ read_consume(a);
+
+ /* If we've already read to end of data, we're done. */
+ if (zip->end_of_entry)
+ return (ARCHIVE_OK);
+
+ /*
+ * If the length is at the beginning, we can skip the
+ * compressed data much more quickly.
+ */
+ bytes_skipped = skip_stream(a, zip->entry_bytes_remaining);
+ if (bytes_skipped < 0)
+ return (ARCHIVE_FATAL);
+ zip->entry_bytes_remaining = 0;
+
+ /* This entry is finished and done. */
+ zip->end_of_entry = 1;
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_7zip_cleanup(struct archive_read *a)
+{
+ struct _7zip *zip;
+
+ zip = (struct _7zip *)(a->format->data);
+ free_StreamsInfo(&(zip->si));
+ free(zip->entries);
+ free(zip->entry_names);
+ free_decompression(a, zip);
+ free(zip->uncompressed_buffer);
+ free(zip->sub_stream_buff[0]);
+ free(zip->sub_stream_buff[1]);
+ free(zip->sub_stream_buff[2]);
+ free(zip->tmp_stream_buff);
+ free(zip);
+ (a->format->data) = NULL;
+ return (ARCHIVE_OK);
+}
+
+static void
+read_consume(struct archive_read *a)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+
+ if (zip->pack_stream_bytes_unconsumed) {
+ __archive_read_consume(a, zip->pack_stream_bytes_unconsumed);
+ zip->stream_offset += zip->pack_stream_bytes_unconsumed;
+ zip->pack_stream_bytes_unconsumed = 0;
+ }
+}
+
+#ifdef HAVE_LZMA_H
+
+/*
+ * Set an error code and choose an error message for liblzma.
+ */
+static void
+set_error(struct archive_read *a, int ret)
+{
+
+ switch (ret) {
+ case LZMA_STREAM_END: /* Found end of stream. */
+ case LZMA_OK: /* Decompressor made some progress. */
+ break;
+ case LZMA_MEM_ERROR:
+ archive_set_error(&a->archive, ENOMEM,
+ "Lzma library error: Cannot allocate memory");
+ break;
+ case LZMA_MEMLIMIT_ERROR:
+ archive_set_error(&a->archive, ENOMEM,
+ "Lzma library error: Out of memory");
+ break;
+ case LZMA_FORMAT_ERROR:
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Lzma library error: format not recognized");
+ break;
+ case LZMA_OPTIONS_ERROR:
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Lzma library error: Invalid options");
+ break;
+ case LZMA_DATA_ERROR:
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Lzma library error: Corrupted input data");
+ break;
+ case LZMA_BUF_ERROR:
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Lzma library error: No progress is possible");
+ break;
+ default:
+ /* Return an error. */
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Lzma decompression failed: Unknown error");
+ break;
+ }
+}
+
+#endif
+
+static unsigned long
+decode_codec_id(const unsigned char *codecId, size_t id_size)
+{
+ unsigned i;
+ unsigned long id = 0;
+
+ for (i = 0; i < id_size; i++) {
+ id <<= 8;
+ id += codecId[i];
+ }
+ return (id);
+}
+
+static void *
+ppmd_alloc(void *p, size_t size)
+{
+ (void)p;
+ return malloc(size);
+}
+static void
+ppmd_free(void *p, void *address)
+{
+ (void)p;
+ free(address);
+}
+static Byte
+ppmd_read(void *p)
+{
+ struct archive_read *a = ((IByteIn*)p)->a;
+ struct _7zip *zip = (struct _7zip *)(a->format->data);
+ Byte b;
+
+ if (zip->ppstream.avail_in == 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated RAR file data");
+ zip->ppstream.overconsumed = 1;
+ return (0);
+ }
+ b = *zip->ppstream.next_in++;
+ zip->ppstream.avail_in--;
+ zip->ppstream.total_in++;
+ return (b);
+}
+
+static ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
+
+static int
+init_decompression(struct archive_read *a, struct _7zip *zip,
+ const struct _7z_coder *coder1, const struct _7z_coder *coder2)
+{
+ int r;
+
+ zip->codec = coder1->codec;
+ zip->codec2 = -1;
+
+ switch (zip->codec) {
+ case _7Z_COPY:
+ case _7Z_BZ2:
+ case _7Z_DEFLATE:
+ case _7Z_PPMD:
+ if (coder2 != NULL) {
+ if (coder2->codec != _7Z_X86 &&
+ coder2->codec != _7Z_X86_BCJ2) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Unsupported filter %lx for %lx",
+ coder2->codec, coder1->codec);
+ return (ARCHIVE_FAILED);
+ }
+ zip->codec2 = coder2->codec;
+ zip->bcj_state = 0;
+ if (coder2->codec == _7Z_X86)
+ x86_Init(zip);
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (zip->codec) {
+ case _7Z_COPY:
+ break;
+
+ case _7Z_LZMA: case _7Z_LZMA2:
+#ifdef HAVE_LZMA_H
+#if LZMA_VERSION_MAJOR >= 5
+/* Effectively disable the limiter. */
+#define LZMA_MEMLIMIT UINT64_MAX
+#else
+/* NOTE: This needs to check memory size which running system has. */
+#define LZMA_MEMLIMIT (1U << 30)
+#endif
+ {
+ lzma_options_delta delta_opt;
+ lzma_filter filters[LZMA_FILTERS_MAX];
+#if LZMA_VERSION < 50000030
+ lzma_filter *ff;
+#endif
+ int fi = 0;
+
+ if (zip->lzstream_valid) {
+ lzma_end(&(zip->lzstream));
+ zip->lzstream_valid = 0;
+ }
+
+ /*
+ * NOTE: liblzma incompletely handle the BCJ+LZMA compressed
+ * data made by 7-Zip because 7-Zip does not add End-Of-
+ * Payload Marker(EOPM) at the end of LZMA compressed data,
+ * and so liblzma cannot know the end of the compressed data
+ * without EOPM. So consequently liblzma will not return last
+ * three or four bytes of uncompressed data because
+ * LZMA_FILTER_X86 filter does not handle input data if its
+ * data size is less than five bytes. If liblzma detect EOPM
+ * or know the uncompressed data size, liblzma will flush out
+ * the remaining that three or four bytes of uncompressed
+ * data. That is why we have to use our converting program
+ * for BCJ+LZMA. If we were able to tell the uncompressed
+ * size to liblzma when using lzma_raw_decoder() liblzma
+ * could correctly deal with BCJ+LZMA. But unfortunately
+ * there is no way to do that.
+ * Discussion about this can be found at XZ Utils forum.
+ */
+ if (coder2 != NULL) {
+ zip->codec2 = coder2->codec;
+
+ filters[fi].options = NULL;
+ switch (zip->codec2) {
+ case _7Z_X86:
+ if (zip->codec == _7Z_LZMA2) {
+ filters[fi].id = LZMA_FILTER_X86;
+ fi++;
+ } else
+ /* Use our filter. */
+ x86_Init(zip);
+ break;
+ case _7Z_X86_BCJ2:
+ /* Use our filter. */
+ zip->bcj_state = 0;
+ break;
+ case _7Z_DELTA:
+ filters[fi].id = LZMA_FILTER_DELTA;
+ memset(&delta_opt, 0, sizeof(delta_opt));
+ delta_opt.type = LZMA_DELTA_TYPE_BYTE;
+ delta_opt.dist = 1;
+ filters[fi].options = &delta_opt;
+ fi++;
+ break;
+ /* Following filters have not been tested yet. */
+ case _7Z_POWERPC:
+ filters[fi].id = LZMA_FILTER_POWERPC;
+ fi++;
+ break;
+ case _7Z_IA64:
+ filters[fi].id = LZMA_FILTER_IA64;
+ fi++;
+ break;
+ case _7Z_ARM:
+ filters[fi].id = LZMA_FILTER_ARM;
+ fi++;
+ break;
+ case _7Z_ARMTHUMB:
+ filters[fi].id = LZMA_FILTER_ARMTHUMB;
+ fi++;
+ break;
+ case _7Z_SPARC:
+ filters[fi].id = LZMA_FILTER_SPARC;
+ fi++;
+ break;
+ default:
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Unexpected codec ID: %lX", zip->codec2);
+ return (ARCHIVE_FAILED);
+ }
+ }
+
+ if (zip->codec == _7Z_LZMA2)
+ filters[fi].id = LZMA_FILTER_LZMA2;
+ else
+ filters[fi].id = LZMA_FILTER_LZMA1;
+ filters[fi].options = NULL;
+#if LZMA_VERSION < 50000030
+ ff = &filters[fi];
+#endif
+ r = lzma_properties_decode(&filters[fi], NULL,
+ coder1->properties, coder1->propertiesSize);
+ if (r != LZMA_OK) {
+ set_error(a, r);
+ return (ARCHIVE_FAILED);
+ }
+ fi++;
+
+ filters[fi].id = LZMA_VLI_UNKNOWN;
+ filters[fi].options = NULL;
+ r = lzma_raw_decoder(&(zip->lzstream), filters);
+#if LZMA_VERSION < 50000030
+ free(ff->options);
+#endif
+ if (r != LZMA_OK) {
+ set_error(a, r);
+ return (ARCHIVE_FAILED);
+ }
+ zip->lzstream_valid = 1;
+ zip->lzstream.total_in = 0;
+ zip->lzstream.total_out = 0;
+ break;
+ }
+#else
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "LZMA codec is unsupported");
+ return (ARCHIVE_FAILED);
+#endif
+ case _7Z_BZ2:
+#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
+ if (zip->bzstream_valid) {
+ BZ2_bzDecompressEnd(&(zip->bzstream));
+ zip->bzstream_valid = 0;
+ }
+ r = BZ2_bzDecompressInit(&(zip->bzstream), 0, 0);
+ if (r == BZ_MEM_ERROR)
+ r = BZ2_bzDecompressInit(&(zip->bzstream), 0, 1);
+ if (r != BZ_OK) {
+ int err = ARCHIVE_ERRNO_MISC;
+ const char *detail = NULL;
+ switch (r) {
+ case BZ_PARAM_ERROR:
+ detail = "invalid setup parameter";
+ break;
+ case BZ_MEM_ERROR:
+ err = ENOMEM;
+ detail = "out of memory";
+ break;
+ case BZ_CONFIG_ERROR:
+ detail = "mis-compiled library";
+ break;
+ }
+ archive_set_error(&a->archive, err,
+ "Internal error initializing decompressor: %s",
+ detail == NULL ? "??" : detail);
+ zip->bzstream_valid = 0;
+ return (ARCHIVE_FAILED);
+ }
+ zip->bzstream_valid = 1;
+ zip->bzstream.total_in_lo32 = 0;
+ zip->bzstream.total_in_hi32 = 0;
+ zip->bzstream.total_out_lo32 = 0;
+ zip->bzstream.total_out_hi32 = 0;
+ break;
+#else
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "BZ2 codec is unsupported");
+ return (ARCHIVE_FAILED);
+#endif
+ case _7Z_DEFLATE:
+#ifdef HAVE_ZLIB_H
+ if (zip->stream_valid)
+ r = inflateReset(&(zip->stream));
+ else
+ r = inflateInit2(&(zip->stream),
+ -15 /* Don't check for zlib header */);
+ if (r != Z_OK) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Couldn't initialize zlib stream.");
+ return (ARCHIVE_FAILED);
+ }
+ zip->stream_valid = 1;
+ zip->stream.total_in = 0;
+ zip->stream.total_out = 0;
+ break;
+#else
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "DEFLATE codec is unsupported");
+ return (ARCHIVE_FAILED);
+#endif
+ case _7Z_PPMD:
+ {
+ unsigned order;
+ uint32_t msize;
+
+ if (zip->ppmd7_valid) {
+ __archive_ppmd7_functions.Ppmd7_Free(
+ &zip->ppmd7_context, &g_szalloc);
+ zip->ppmd7_valid = 0;
+ }
+
+ if (coder1->propertiesSize < 5) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Malformed PPMd parameter");
+ return (ARCHIVE_FAILED);
+ }
+ order = coder1->properties[0];
+ msize = archive_le32dec(&(coder1->properties[1]));
+ if (order < PPMD7_MIN_ORDER || order > PPMD7_MAX_ORDER ||
+ msize < PPMD7_MIN_MEM_SIZE || msize > PPMD7_MAX_MEM_SIZE) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Malformed PPMd parameter");
+ return (ARCHIVE_FAILED);
+ }
+ __archive_ppmd7_functions.Ppmd7_Construct(&zip->ppmd7_context);
+ r = __archive_ppmd7_functions.Ppmd7_Alloc(
+ &zip->ppmd7_context, msize, &g_szalloc);
+ if (r == 0) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Coludn't allocate memory for PPMd");
+ return (ARCHIVE_FATAL);
+ }
+ __archive_ppmd7_functions.Ppmd7_Init(
+ &zip->ppmd7_context, order);
+ __archive_ppmd7_functions.Ppmd7z_RangeDec_CreateVTable(
+ &zip->range_dec);
+ zip->ppmd7_valid = 1;
+ zip->ppmd7_stat = 0;
+ zip->ppstream.overconsumed = 0;
+ zip->ppstream.total_in = 0;
+ zip->ppstream.total_out = 0;
+ break;
+ }
+ case _7Z_X86:
+ case _7Z_X86_BCJ2:
+ case _7Z_POWERPC:
+ case _7Z_IA64:
+ case _7Z_ARM:
+ case _7Z_ARMTHUMB:
+ case _7Z_SPARC:
+ case _7Z_DELTA:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Unexpected codec ID: %lX", zip->codec);
+ return (ARCHIVE_FAILED);
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Unknown codec ID: %lX", zip->codec);
+ return (ARCHIVE_FAILED);
+ }
+
+ return (ARCHIVE_OK);
+}
+
+static int
+decompress(struct archive_read *a, struct _7zip *zip,
+ void *buff, size_t *outbytes, const void *b, size_t *used)
+{
+ const uint8_t *t_next_in;
+ uint8_t *t_next_out;
+ size_t o_avail_in, o_avail_out;
+ size_t t_avail_in, t_avail_out;
+ uint8_t *bcj2_next_out;
+ size_t bcj2_avail_out;
+ int r, ret = ARCHIVE_OK;
+
+ t_avail_in = o_avail_in = *used;
+ t_avail_out = o_avail_out = *outbytes;
+ t_next_in = b;
+ t_next_out = buff;
+
+ if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) {
+ int i;
+
+ /* Do not copy out the BCJ remaining bytes when the output
+ * buffer size is less than five bytes. */
+ if (o_avail_in != 0 && t_avail_out < 5 && zip->odd_bcj_size) {
+ *used = 0;
+ *outbytes = 0;
+ return (ret);
+ }
+ for (i = 0; zip->odd_bcj_size > 0 && t_avail_out; i++) {
+ *t_next_out++ = zip->odd_bcj[i];
+ t_avail_out--;
+ zip->odd_bcj_size--;
+ }
+ if (o_avail_in == 0 || t_avail_out == 0) {
+ *used = o_avail_in - t_avail_in;
+ *outbytes = o_avail_out - t_avail_out;
+ if (o_avail_in == 0)
+ ret = ARCHIVE_EOF;
+ return (ret);
+ }
+ }
+
+ bcj2_next_out = t_next_out;
+ bcj2_avail_out = t_avail_out;
+ if (zip->codec2 == _7Z_X86_BCJ2) {
+ /*
+ * Decord a remaining decompressed main stream for BCJ2.
+ */
+ if (zip->tmp_stream_bytes_remaining) {
+ ssize_t bytes;
+ size_t remaining = zip->tmp_stream_bytes_remaining;
+ bytes = Bcj2_Decode(zip, t_next_out, t_avail_out);
+ if (bytes < 0) {
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "BCJ2 conversion Failed");
+ return (ARCHIVE_FAILED);
+ }
+ zip->main_stream_bytes_remaining -=
+ remaining - zip->tmp_stream_bytes_remaining;
+ t_avail_out -= bytes;
+ if (o_avail_in == 0 || t_avail_out == 0) {
+ *used = 0;
+ *outbytes = o_avail_out - t_avail_out;
+ if (o_avail_in == 0 &&
+ zip->tmp_stream_bytes_remaining)
+ ret = ARCHIVE_EOF;
+ return (ret);
+ }
+ t_next_out += bytes;
+ bcj2_next_out = t_next_out;
+ bcj2_avail_out = t_avail_out;
+ }
+ t_next_out = zip->tmp_stream_buff;
+ t_avail_out = zip->tmp_stream_buff_size;
+ }
+
+ switch (zip->codec) {
+ case _7Z_COPY:
+ {
+ size_t bytes =
+ (t_avail_in > t_avail_out)?t_avail_out:t_avail_in;
+
+ memcpy(t_next_out, t_next_in, bytes);
+ t_avail_in -= bytes;
+ t_avail_out -= bytes;
+ if (o_avail_in == 0)
+ ret = ARCHIVE_EOF;
+ break;
+ }
+#ifdef HAVE_LZMA_H
+ case _7Z_LZMA: case _7Z_LZMA2:
+ zip->lzstream.next_in = t_next_in;
+ zip->lzstream.avail_in = t_avail_in;
+ zip->lzstream.next_out = t_next_out;
+ zip->lzstream.avail_out = t_avail_out;
+
+ r = lzma_code(&(zip->lzstream), LZMA_RUN);
+ switch (r) {
+ case LZMA_STREAM_END: /* Found end of stream. */
+ lzma_end(&(zip->lzstream));
+ zip->lzstream_valid = 0;
+ ret = ARCHIVE_EOF;
+ break;
+ case LZMA_OK: /* Decompressor made some progress. */
+ break;
+ default:
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Decompression failed(%d)",
+ r);
+ return (ARCHIVE_FAILED);
+ }
+ t_avail_in = zip->lzstream.avail_in;
+ t_avail_out = zip->lzstream.avail_out;
+ break;
+#endif
+#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
+ case _7Z_BZ2:
+ zip->bzstream.next_in = (char *)(uintptr_t)t_next_in;
+ zip->bzstream.avail_in = t_avail_in;
+ zip->bzstream.next_out = (char *)(uintptr_t)t_next_out;
+ zip->bzstream.avail_out = t_avail_out;
+ r = BZ2_bzDecompress(&(zip->bzstream));
+ switch (r) {
+ case BZ_STREAM_END: /* Found end of stream. */
+ switch (BZ2_bzDecompressEnd(&(zip->bzstream))) {
+ case BZ_OK:
+ break;
+ default:
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up decompressor");
+ return (ARCHIVE_FAILED);
+ }
+ zip->bzstream_valid = 0;
+ ret = ARCHIVE_EOF;
+ break;
+ case BZ_OK: /* Decompressor made some progress. */
+ break;
+ default:
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "bzip decompression failed");
+ return (ARCHIVE_FAILED);
+ }
+ t_avail_in = zip->bzstream.avail_in;
+ t_avail_out = zip->bzstream.avail_out;
+ break;
+#endif
+#ifdef HAVE_ZLIB_H
+ case _7Z_DEFLATE:
+ zip->stream.next_in = (Bytef *)(uintptr_t)t_next_in;
+ zip->stream.avail_in = t_avail_in;
+ zip->stream.next_out = t_next_out;
+ zip->stream.avail_out = t_avail_out;
+ r = inflate(&(zip->stream), 0);
+ switch (r) {
+ case Z_STREAM_END: /* Found end of stream. */
+ ret = ARCHIVE_EOF;
+ break;
+ case Z_OK: /* Decompressor made some progress.*/
+ break;
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "File decompression failed (%d)", r);
+ return (ARCHIVE_FAILED);
+ }
+ t_avail_in = zip->stream.avail_in;
+ t_avail_out = zip->stream.avail_out;
+ break;
+#endif
+ case _7Z_PPMD:
+ {
+ uint64_t flush_bytes;
+
+ if (!zip->ppmd7_valid || zip->ppmd7_stat < 0 ||
+ t_avail_out <= 0) {
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Decompression internal error");
+ return (ARCHIVE_FAILED);
+ }
+ zip->ppstream.next_in = t_next_in;
+ zip->ppstream.avail_in = t_avail_in;
+ zip->ppstream.next_out = t_next_out;
+ zip->ppstream.avail_out = t_avail_out;
+ if (zip->ppmd7_stat == 0) {
+ zip->bytein.a = a;
+ zip->bytein.Read = &ppmd_read;
+ zip->range_dec.Stream = &zip->bytein;
+ r = __archive_ppmd7_functions.Ppmd7z_RangeDec_Init(
+ &(zip->range_dec));
+ if (r == 0) {
+ zip->ppmd7_stat = -1;
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Failed to initialize PPMd range decorder");
+ return (ARCHIVE_FAILED);
+ }
+ if (zip->ppstream.overconsumed) {
+ zip->ppmd7_stat = -1;
+ return (ARCHIVE_FAILED);
+ }
+ zip->ppmd7_stat = 1;
+ }
+
+ if (t_avail_in == 0)
+ /* XXX Flush out remaining decoded data XXX */
+ flush_bytes = zip->folder_outbytes_remaining;
+ else
+ flush_bytes = 0;
+
+ do {
+ int sym;
+
+ sym = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
+ &(zip->ppmd7_context), &(zip->range_dec.p));
+ if (sym < 0) {
+ zip->ppmd7_stat = -1;
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Failed to decode PPMd");
+ return (ARCHIVE_FAILED);
+ }
+ if (zip->ppstream.overconsumed) {
+ zip->ppmd7_stat = -1;
+ return (ARCHIVE_FAILED);
+ }
+ *zip->ppstream.next_out++ = (unsigned char)sym;
+ zip->ppstream.avail_out--;
+ zip->ppstream.total_out++;
+ if (flush_bytes)
+ flush_bytes--;
+ } while (zip->ppstream.avail_out &&
+ (zip->ppstream.avail_in || flush_bytes));
+
+ t_avail_in = zip->ppstream.avail_in;
+ t_avail_out = zip->ppstream.avail_out;
+ break;
+ }
+ default:
+ archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
+ "Decompression internal error");
+ return (ARCHIVE_FAILED);
+ }
+ if (ret != ARCHIVE_OK && ret != ARCHIVE_EOF)
+ return (ret);
+
+ *used = o_avail_in - t_avail_in;
+ *outbytes = o_avail_out - t_avail_out;
+
+ /*
+ * Decord BCJ.
+ */
+ if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) {
+ size_t l = x86_Convert(zip, buff, *outbytes);
+ zip->odd_bcj_size = *outbytes - l;
+ if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 &&
+ o_avail_in && ret != ARCHIVE_EOF) {
+ memcpy(zip->odd_bcj, ((unsigned char *)buff) + l,
+ zip->odd_bcj_size);
+ *outbytes = l;
+ } else
+ zip->odd_bcj_size = 0;
+ }
+
+ /*
+ * Decord BCJ2 with a decompressed main stream.
+ */
+ if (zip->codec2 == _7Z_X86_BCJ2) {
+ ssize_t bytes;
+
+ zip->tmp_stream_bytes_avail =
+ zip->tmp_stream_buff_size - t_avail_out;
+ if (zip->tmp_stream_bytes_avail >
+ zip->main_stream_bytes_remaining)
+ zip->tmp_stream_bytes_avail =
+ zip->main_stream_bytes_remaining;
+ zip->tmp_stream_bytes_remaining = zip->tmp_stream_bytes_avail;
+ bytes = Bcj2_Decode(zip, bcj2_next_out, bcj2_avail_out);
+ if (bytes < 0) {
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC, "BCJ2 conversion Failed");
+ return (ARCHIVE_FAILED);
+ }
+ zip->main_stream_bytes_remaining -=
+ zip->tmp_stream_bytes_avail
+ - zip->tmp_stream_bytes_remaining;
+ bcj2_avail_out -= bytes;
+ *outbytes = o_avail_out - bcj2_avail_out;
+ }
+
+ return (ret);
+}
+
+static int
+free_decompression(struct archive_read *a, struct _7zip *zip)
+{
+ int r = ARCHIVE_OK;
+
+#ifdef HAVE_LZMA_H
+ if (zip->lzstream_valid)
+ lzma_end(&(zip->lzstream));
+#endif
+#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
+ if (zip->bzstream_valid) {
+ if (BZ2_bzDecompressEnd(&(zip->bzstream)) != BZ_OK) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up bzip2 decompressor");
+ r = ARCHIVE_FATAL;
+ }
+ zip->bzstream_valid = 0;
+ }
+#endif
+#ifdef HAVE_ZLIB_H
+ if (zip->stream_valid) {
+ if (inflateEnd(&(zip->stream)) != Z_OK) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up zlib decompressor");
+ r = ARCHIVE_FATAL;
+ }
+ zip->stream_valid = 0;
+ }
+#endif
+ if (zip->ppmd7_valid) {
+ __archive_ppmd7_functions.Ppmd7_Free(
+ &zip->ppmd7_context, &g_szalloc);
+ zip->ppmd7_valid = 0;
+ }
+ return (r);
+}
+
+static int
+parse_7zip_uint64(struct archive_read *a, uint64_t *val)
+{
+ const unsigned char *p;
+ unsigned char avail, mask;
+ int i;
+
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ avail = *p;
+ mask = 0x80;
+ *val = 0;
+ for (i = 0; i < 8; i++) {
+ if (avail & mask) {
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ *val |= ((uint64_t)*p) << (8 * i);
+ mask >>= 1;
+ continue;
+ }
+ *val += (avail & (mask -1)) << (8 * i);
+ break;
+ }
+ return (0);
+}
+
+static int
+read_Bools(struct archive_read *a, unsigned char *data, size_t num)
+{
+ const unsigned char *p;
+ unsigned i, mask = 0, avail = 0;
+
+ for (i = 0; i < num; i++) {
+ if (mask == 0) {
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ avail = *p;
+ mask = 0x80;
+ }
+ data[i] = (avail & mask)?1:0;
+ mask >>= 1;
+ }
+ return (0);
+}
+
+static void
+free_Digest(struct _7z_digests *d)
+{
+ free(d->defineds);
+ free(d->digests);
+}
+
+static int
+read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num)
+{
+ const unsigned char *p;
+ unsigned i;
+
+ memset(d, 0, sizeof(*d));
+
+
+ d->defineds = malloc(num);
+ if (d->defineds == NULL)
+ return (-1);
+ /*
+ * Read Bools.
+ */
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ if (*p == 0) {
+ if (read_Bools(a, d->defineds, num) < 0)
+ return (-1);
+ } else
+ /* All are defined */
+ memset(d->defineds, 1, num);
+
+ d->digests = calloc(num, sizeof(*d->digests));
+ if (d->digests == NULL)
+ return (-1);
+ for (i = 0; i < num; i++) {
+ if (d->defineds[i]) {
+ if ((p = header_bytes(a, 4)) == NULL)
+ return (-1);
+ d->digests[i] = archive_le32dec(p);
+ }
+ }
+
+ return (0);
+}
+
+static void
+free_PackInfo(struct _7z_pack_info *pi)
+{
+ free(pi->sizes);
+ free(pi->positions);
+ free_Digest(&(pi->digest));
+}
+
+static int
+read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
+{
+ const unsigned char *p;
+ unsigned i;
+
+ memset(pi, 0, sizeof(*pi));
+
+ /*
+ * Read PackPos.
+ */
+ if (parse_7zip_uint64(a, &(pi->pos)) < 0)
+ return (-1);
+
+ /*
+ * Read NumPackStreams.
+ */
+ if (parse_7zip_uint64(a, &(pi->numPackStreams)) < 0)
+ return (-1);
+ if (pi->numPackStreams == 0)
+ return (-1);
+ if (1000000 < pi->numPackStreams)
+ return (-1);
+
+ /*
+ * Read PackSizes[num]
+ */
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ if (*p == kEnd)
+ /* PackSizes[num] are not present. */
+ return (0);
+ if (*p != kSize)
+ return (-1);
+ pi->sizes = calloc(pi->numPackStreams, sizeof(uint64_t));
+ pi->positions = calloc(pi->numPackStreams, sizeof(uint64_t));
+ if (pi->sizes == NULL || pi->positions == NULL)
+ return (-1);
+
+ for (i = 0; i < pi->numPackStreams; i++) {
+ if (parse_7zip_uint64(a, &(pi->sizes[i])) < 0)
+ return (-1);
+ }
+
+ /*
+ * Read PackStreamDigests[num]
+ */
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ if (*p == kEnd) {
+ /* PackStreamDigests[num] are not present. */
+ pi->digest.defineds =
+ calloc(pi->numPackStreams, sizeof(*pi->digest.defineds));
+ pi->digest.digests =
+ calloc(pi->numPackStreams, sizeof(*pi->digest.digests));
+ if (pi->digest.defineds == NULL || pi->digest.digests == NULL)
+ return (-1);
+ return (0);
+ }
+
+ if (*p != kSize)
+ return (-1);
+
+ if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0)
+ return (-1);
+
+ /*
+ * Must be marked by kEnd.
+ */
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ if (*p != kEnd)
+ return (-1);
+ return (0);
+}
+
+static void
+free_Folder(struct _7z_folder *f)
+{
+ unsigned i;
+
+ if (f->coders) {
+ for (i = 0; i< f->numCoders; i++) {
+ free(f->coders[i].properties);
+ }
+ free(f->coders);
+ }
+ free(f->bindPairs);
+ free(f->packedStreams);
+ free(f->unPackSize);
+}
+
+static int
+read_Folder(struct archive_read *a, struct _7z_folder *f)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ const unsigned char *p;
+ uint64_t numInStreamsTotal = 0;
+ uint64_t numOutStreamsTotal = 0;
+ unsigned i;
+
+ memset(f, 0, sizeof(*f));
+
+ /*
+ * Read NumCoders.
+ */
+ if (parse_7zip_uint64(a, &(f->numCoders)) < 0)
+ return (-1);
+ if (f->numCoders > 4)
+ /* Too many coders. */
+ return (-1);
+
+ f->coders = calloc(f->numCoders, sizeof(*f->coders));
+ if (f->coders == NULL)
+ return (-1);
+ for (i = 0; i< f->numCoders; i++) {
+ size_t codec_size;
+ int simple, attr;
+
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ /*
+ * 0:3 CodecIdSize
+ * 4: 0 - IsSimple
+ * 1 - Is not Simple
+ * 5: 0 - No Attributes
+ * 1 - There are Attributes;
+ * 7: Must be zero.
+ */
+ codec_size = *p & 0xf;
+ simple = (*p & 0x10)?0:1;
+ attr = *p & 0x20;
+ if (*p & 0x80)
+ return (-1);/* Not supported. */
+
+ /*
+ * Read Decompression Method IDs.
+ */
+ if ((p = header_bytes(a, codec_size)) == NULL)
+ return (-1);
+
+ f->coders[i].codec = decode_codec_id(p, codec_size);
+
+ if (simple) {
+ f->coders[i].numInStreams = 1;
+ f->coders[i].numOutStreams = 1;
+ } else {
+ if (parse_7zip_uint64(
+ a, &(f->coders[i].numInStreams)) < 0)
+ return (-1);
+ if (1000000 < f->coders[i].numInStreams)
+ return (-1);
+ if (parse_7zip_uint64(
+ a, &(f->coders[i].numOutStreams)) < 0)
+ return (-1);
+ if (1000000 < f->coders[i].numOutStreams)
+ return (-1);
+ }
+
+ if (attr) {
+ if (parse_7zip_uint64(
+ a, &(f->coders[i].propertiesSize)) < 0)
+ return (-1);
+ if ((p = header_bytes(
+ a, f->coders[i].propertiesSize)) == NULL)
+ return (-1);
+ f->coders[i].properties =
+ malloc(f->coders[i].propertiesSize);
+ if (f->coders[i].properties == NULL)
+ return (-1);
+ memcpy(f->coders[i].properties, p,
+ f->coders[i].propertiesSize);
+ }
+
+ numInStreamsTotal += f->coders[i].numInStreams;
+ numOutStreamsTotal += f->coders[i].numOutStreams;
+ }
+
+ if (numOutStreamsTotal == 0 ||
+ numInStreamsTotal < numOutStreamsTotal-1)
+ return (-1);
+
+ f->numBindPairs = numOutStreamsTotal - 1;
+ if (zip->header_bytes_remaining < f->numBindPairs)
+ return (-1);
+ f->bindPairs = calloc(f->numBindPairs, sizeof(*f->bindPairs));
+ if (f->bindPairs == NULL)
+ return (-1);
+ for (i = 0; i < f->numBindPairs; i++) {
+ if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
+ return (-1);
+ if (1000000 < f->bindPairs[i].inIndex)
+ return (-1);
+ if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0)
+ return (-1);
+ if (1000000 < f->bindPairs[i].outIndex)
+ return (-1);
+ }
+
+ f->numPackedStreams = numInStreamsTotal - f->numBindPairs;
+ f->packedStreams =
+ calloc(f->numPackedStreams, sizeof(*f->packedStreams));
+ if (f->packedStreams == NULL)
+ return (-1);
+ if (f->numPackedStreams == 1) {
+ for (i = 0; i < numInStreamsTotal; i++) {
+ unsigned j;
+ for (j = 0; j < f->numBindPairs; j++) {
+ if (f->bindPairs[j].inIndex == i)
+ break;
+ }
+ if (j == f->numBindPairs)
+ break;
+ }
+ if (i == numInStreamsTotal)
+ return (-1);
+ f->packedStreams[0] = i;
+ } else {
+ for (i = 0; i < f->numPackedStreams; i++) {
+ if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)
+ return (-1);
+ if (1000000 < f->packedStreams[i])
+ return (-1);
+ }
+ }
+ f->numInStreams = numInStreamsTotal;
+ f->numOutStreams = numOutStreamsTotal;
+
+ return (0);
+}
+
+static void
+free_CodersInfo(struct _7z_coders_info *ci)
+{
+ unsigned i;
+
+ if (ci->folders) {
+ for (i = 0; i < ci->numFolders; i++)
+ free_Folder(&(ci->folders[i]));
+ free(ci->folders);
+ }
+}
+
+static int
+read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
+{
+ const unsigned char *p;
+ struct _7z_digests digest;
+ unsigned i;
+
+ memset(ci, 0, sizeof(*ci));
+ memset(&digest, 0, sizeof(digest));
+
+ if ((p = header_bytes(a, 1)) == NULL)
+ goto failed;
+ if (*p != kFolder)
+ goto failed;
+
+ /*
+ * Read NumFolders.
+ */
+ if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
+ goto failed;
+ if (1000000 < ci->numFolders)
+ return (-1);
+
+ /*
+ * Read External.
+ */
+ if ((p = header_bytes(a, 1)) == NULL)
+ goto failed;
+ switch (*p) {
+ case 0:
+ ci->folders = calloc(ci->numFolders, sizeof(*ci->folders));
+ if (ci->folders == NULL)
+ return (-1);
+ for (i = 0; i < ci->numFolders; i++) {
+ if (read_Folder(a, &(ci->folders[i])) < 0)
+ goto failed;
+ }
+ break;
+ case 1:
+ if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
+ return (-1);
+ if (1000000 < ci->dataStreamIndex)
+ return (-1);
+ break;
+ }
+
+ if ((p = header_bytes(a, 1)) == NULL)
+ goto failed;
+ if (*p != kCodersUnPackSize)
+ goto failed;
+
+ for (i = 0; i < ci->numFolders; i++) {
+ struct _7z_folder *folder = &(ci->folders[i]);
+ unsigned j;
+
+ folder->unPackSize =
+ calloc(folder->numOutStreams, sizeof(*folder->unPackSize));
+ if (folder->unPackSize == NULL)
+ goto failed;
+ for (j = 0; j < folder->numOutStreams; j++) {
+ if (parse_7zip_uint64(a, &(folder->unPackSize[j])) < 0)
+ goto failed;
+ }
+ }
+
+ /*
+ * Read CRCs.
+ */
+ if ((p = header_bytes(a, 1)) == NULL)
+ goto failed;
+ if (*p == kEnd)
+ return (0);
+ if (*p != kCRC)
+ goto failed;
+ if (read_Digests(a, &digest, ci->numFolders) < 0)
+ goto failed;
+ for (i = 0; i < ci->numFolders; i++) {
+ ci->folders[i].digest_defined = digest.defineds[i];
+ ci->folders[i].digest = digest.digests[i];
+ }
+
+ /*
+ * Must be kEnd.
+ */
+ if ((p = header_bytes(a, 1)) == NULL)
+ goto failed;
+ if (*p != kEnd)
+ goto failed;
+ free_Digest(&digest);
+ return (0);
+failed:
+ free_Digest(&digest);
+ return (-1);
+}
+
+static uint64_t
+folder_uncompressed_size(struct _7z_folder *f)
+{
+ int n = f->numOutStreams;
+ unsigned pairs = f->numBindPairs;
+
+ while (--n >= 0) {
+ unsigned i;
+ for (i = 0; i < pairs; i++) {
+ if (f->bindPairs[i].outIndex == (uint64_t)n)
+ break;
+ }
+ if (i >= pairs)
+ return (f->unPackSize[n]);
+ }
+ return (0);
+}
+
+static void
+free_SubStreamsInfo(struct _7z_substream_info *ss)
+{
+ free(ss->unpackSizes);
+ free(ss->digestsDefined);
+ free(ss->digests);
+}
+
+static int
+read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
+ struct _7z_folder *f, size_t numFolders)
+{
+ const unsigned char *p;
+ uint64_t *usizes;
+ size_t unpack_streams;
+ int type;
+ unsigned i;
+ uint32_t numDigests;
+
+ memset(ss, 0, sizeof(*ss));
+
+ for (i = 0; i < numFolders; i++)
+ f[i].numUnpackStreams = 1;
+
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ type = *p;
+
+ if (type == kNumUnPackStream) {
+ unpack_streams = 0;
+ for (i = 0; i < numFolders; i++) {
+ if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)
+ return (-1);
+ if (1000000 < f[i].numUnpackStreams)
+ return (-1);
+ unpack_streams += f[i].numUnpackStreams;
+ }
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ type = *p;
+ } else
+ unpack_streams = numFolders;
+
+ ss->unpack_streams = unpack_streams;
+ if (unpack_streams) {
+ ss->unpackSizes = calloc(unpack_streams,
+ sizeof(*ss->unpackSizes));
+ ss->digestsDefined = calloc(unpack_streams,
+ sizeof(*ss->digestsDefined));
+ ss->digests = calloc(unpack_streams,
+ sizeof(*ss->digests));
+ if (ss->unpackSizes == NULL || ss->digestsDefined == NULL ||
+ ss->digests == NULL)
+ return (-1);
+ }
+
+ usizes = ss->unpackSizes;
+ for (i = 0; i < numFolders; i++) {
+ unsigned pack;
+ uint64_t sum;
+
+ if (f[i].numUnpackStreams == 0)
+ continue;
+
+ sum = 0;
+ if (type == kSize) {
+ for (pack = 1; pack < f[i].numUnpackStreams; pack++) {
+ if (parse_7zip_uint64(a, usizes) < 0)
+ return (-1);
+ sum += *usizes++;
+ }
+ }
+ *usizes++ = folder_uncompressed_size(&f[i]) - sum;
+ }
+
+ if (type == kSize) {
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ type = *p;
+ }
+
+ for (i = 0; i < unpack_streams; i++) {
+ ss->digestsDefined[i] = 0;
+ ss->digests[i] = 0;
+ }
+
+ numDigests = 0;
+ for (i = 0; i < numFolders; i++) {
+ if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)
+ numDigests += f[i].numUnpackStreams;
+ }
+
+ if (type == kCRC) {
+ struct _7z_digests tmpDigests;
+ unsigned char *digestsDefined = ss->digestsDefined;
+ uint32_t * digests = ss->digests;
+ int di = 0;
+
+ memset(&tmpDigests, 0, sizeof(tmpDigests));
+ if (read_Digests(a, &(tmpDigests), numDigests) < 0) {
+ free_Digest(&tmpDigests);
+ return (-1);
+ }
+ for (i = 0; i < numFolders; i++) {
+ if (f[i].numUnpackStreams == 1 && f[i].digest_defined) {
+ *digestsDefined++ = 1;
+ *digests++ = f[i].digest;
+ } else {
+ unsigned j;
+
+ for (j = 0; j < f[i].numUnpackStreams;
+ j++, di++) {
+ *digestsDefined++ =
+ tmpDigests.defineds[di];
+ *digests++ =
+ tmpDigests.digests[di];
+ }
+ }
+ }
+ free_Digest(&tmpDigests);
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ type = *p;
+ }
+
+ /*
+ * Must be kEnd.
+ */
+ if (type != kEnd)
+ return (-1);
+ return (0);
+}
+
+static void
+free_StreamsInfo(struct _7z_stream_info *si)
+{
+ free_PackInfo(&(si->pi));
+ free_CodersInfo(&(si->ci));
+ free_SubStreamsInfo(&(si->ss));
+}
+
+static int
+read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ const unsigned char *p;
+ unsigned i;
+
+ memset(si, 0, sizeof(*si));
+
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ if (*p == kPackInfo) {
+ uint64_t packPos;
+
+ if (read_PackInfo(a, &(si->pi)) < 0)
+ return (-1);
+
+ if (si->pi.positions == NULL || si->pi.sizes == NULL)
+ return (-1);
+ /*
+ * Calculate packed stream positions.
+ */
+ packPos = si->pi.pos;
+ for (i = 0; i < si->pi.numPackStreams; i++) {
+ si->pi.positions[i] = packPos;
+ packPos += si->pi.sizes[i];
+ if (packPos > zip->header_offset)
+ return (-1);
+ }
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ }
+ if (*p == kUnPackInfo) {
+ uint32_t packIndex;
+ struct _7z_folder *f;
+
+ if (read_CodersInfo(a, &(si->ci)) < 0)
+ return (-1);
+
+ /*
+ * Calculate packed stream indexes.
+ */
+ packIndex = 0;
+ f = si->ci.folders;
+ for (i = 0; i < si->ci.numFolders; i++) {
+ f[i].packIndex = packIndex;
+ packIndex += f[i].numPackedStreams;
+ if (packIndex > si->pi.numPackStreams)
+ return (-1);
+ }
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ }
+
+ if (*p == kSubStreamsInfo) {
+ if (read_SubStreamsInfo(a, &(si->ss),
+ si->ci.folders, si->ci.numFolders) < 0)
+ return (-1);
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ }
+
+ /*
+ * Must be kEnd.
+ */
+ if (*p != kEnd)
+ return (-1);
+ return (0);
+}
+
+static void
+free_Header(struct _7z_header_info *h)
+{
+ free(h->emptyStreamBools);
+ free(h->emptyFileBools);
+ free(h->antiBools);
+ free(h->attrBools);
+}
+
+static int
+read_Header(struct archive_read *a, struct _7z_header_info *h,
+ int check_header_id)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ const unsigned char *p;
+ struct _7z_folder *folders;
+ struct _7z_stream_info *si = &(zip->si);
+ struct _7zip_entry *entries;
+ uint32_t folderIndex, indexInFolder;
+ unsigned i;
+ int eindex, empty_streams, sindex;
+
+ if (check_header_id) {
+ /*
+ * Read Header.
+ */
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ if (*p != kHeader)
+ return (-1);
+ }
+
+ /*
+ * Read ArchiveProperties.
+ */
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ if (*p == kArchiveProperties) {
+ for (;;) {
+ uint64_t size;
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ if (*p == 0)
+ break;
+ if (parse_7zip_uint64(a, &size) < 0)
+ return (-1);
+ }
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ }
+
+ /*
+ * Read MainStreamsInfo.
+ */
+ if (*p == kMainStreamsInfo) {
+ if (read_StreamsInfo(a, &(zip->si)) < 0)
+ return (-1);
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ }
+ if (*p == kEnd)
+ return (0);
+
+ /*
+ * Read FilesInfo.
+ */
+ if (*p != kFilesInfo)
+ return (-1);
+
+ if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
+ return (-1);
+ if (1000000 < zip->numFiles)
+ return (-1);
+
+ zip->entries = calloc(zip->numFiles, sizeof(*zip->entries));
+ if (zip->entries == NULL)
+ return (-1);
+ entries = zip->entries;
+
+ empty_streams = 0;
+ for (;;) {
+ int type;
+ uint64_t size;
+ size_t ll;
+
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ type = *p;
+ if (type == kEnd)
+ break;
+
+ if (parse_7zip_uint64(a, &size) < 0)
+ return (-1);
+ if (zip->header_bytes_remaining < size)
+ return (-1);
+ ll = (size_t)size;
+
+ switch (type) {
+ case kEmptyStream:
+ h->emptyStreamBools = calloc(zip->numFiles,
+ sizeof(*h->emptyStreamBools));
+ if (h->emptyStreamBools == NULL)
+ return (-1);
+ if (read_Bools(
+ a, h->emptyStreamBools, zip->numFiles) < 0)
+ return (-1);
+ empty_streams = 0;
+ for (i = 0; i < zip->numFiles; i++) {
+ if (h->emptyStreamBools[i])
+ empty_streams++;
+ }
+ break;
+ case kEmptyFile:
+ h->emptyFileBools = calloc(empty_streams,
+ sizeof(*h->emptyFileBools));
+ if (h->emptyFileBools == NULL)
+ return (-1);
+ if (read_Bools(a, h->emptyFileBools, empty_streams) < 0)
+ return (-1);
+ break;
+ case kAnti:
+ h->antiBools = calloc(empty_streams,
+ sizeof(*h->antiBools));
+ if (h->antiBools == NULL)
+ return (-1);
+ if (read_Bools(a, h->antiBools, empty_streams) < 0)
+ return (-1);
+ break;
+ case kCTime:
+ case kATime:
+ case kMTime:
+ if (read_Times(a, h, type) < 0)
+ return (-1);
+ break;
+ case kName:
+ {
+ unsigned char *np;
+ size_t nl, nb;
+
+ /* Skip one byte. */
+ if ((p = header_bytes(a, 1)) == NULL)
+ return (-1);
+ ll--;
+
+ if ((ll & 1) || ll < zip->numFiles * 4)
+ return (-1);
+
+ zip->entry_names = malloc(ll);
+ if (zip->entry_names == NULL)
+ return (-1);
+ np = zip->entry_names;
+ nb = ll;
+ /*
+ * Copy whole file names.
+ * NOTE: This loop prevents from expanding
+ * the uncompressed buffer in order not to
+ * use extra memory resource.
+ */
+ while (nb) {
+ size_t b;
+ if (nb > UBUFF_SIZE)
+ b = UBUFF_SIZE;
+ else
+ b = nb;
+ if ((p = header_bytes(a, b)) == NULL)
+ return (-1);
+ memcpy(np, p, b);
+ np += b;
+ nb -= b;
+ }
+ np = zip->entry_names;
+ nl = ll;
+
+ for (i = 0; i < zip->numFiles; i++) {
+ entries[i].utf16name = np;
+#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
+ entries[i].wname = (wchar_t *)np;
+#endif
+
+ /* Find a terminator. */
+ while (nl >= 2 && (np[0] || np[1])) {
+ np += 2;
+ nl -= 2;
+ }
+ if (nl < 2)
+ return (-1);/* Terminator not found */
+ entries[i].name_len = np - entries[i].utf16name;
+ np += 2;
+ nl -= 2;
+ }
+ break;
+ }
+ case kAttributes:
+ {
+ int allAreDefined;
+
+ if ((p = header_bytes(a, 2)) == NULL)
+ return (-1);
+ allAreDefined = *p;
+ h->attrBools = calloc(zip->numFiles,
+ sizeof(*h->attrBools));
+ if (h->attrBools == NULL)
+ return (-1);
+ if (allAreDefined)
+ memset(h->attrBools, 1, zip->numFiles);
+ else {
+ if (read_Bools(a, h->attrBools,
+ zip->numFiles) < 0)
+ return (-1);
+ }
+ for (i = 0; i < zip->numFiles; i++) {
+ if (h->attrBools[i]) {
+ if ((p = header_bytes(a, 4)) == NULL)
+ return (-1);
+ entries[i].attr = archive_le32dec(p);
+ }
+ }
+ break;
+ }
+ default:
+ if (header_bytes(a, ll) == NULL)
+ return (-1);
+ break;
+ }
+ }
+
+ /*
+ * Set up entry's attributes.
+ */
+ folders = si->ci.folders;
+ eindex = sindex = 0;
+ folderIndex = indexInFolder = 0;
+ for (i = 0; i < zip->numFiles; i++) {
+ if (h->emptyStreamBools == NULL || h->emptyStreamBools[i] == 0)
+ entries[i].flg |= HAS_STREAM;
+ /* The high 16 bits of attributes is a posix file mode. */
+ entries[i].mode = entries[i].attr >> 16;
+ if (entries[i].flg & HAS_STREAM) {
+ if ((size_t)sindex >= si->ss.unpack_streams)
+ return (-1);
+ if (entries[i].mode == 0)
+ entries[i].mode = AE_IFREG | 0777;
+ if (si->ss.digestsDefined[sindex])
+ entries[i].flg |= CRC32_IS_SET;
+ entries[i].ssIndex = sindex;
+ sindex++;
+ } else {
+ int dir;
+ if (h->emptyFileBools == NULL)
+ dir = 1;
+ else {
+ if (h->emptyFileBools[eindex])
+ dir = 0;
+ else
+ dir = 1;
+ eindex++;
+ }
+ if (entries[i].mode == 0) {
+ if (dir)
+ entries[i].mode = AE_IFDIR | 0777;
+ else
+ entries[i].mode = AE_IFREG | 0777;
+ } else if (dir &&
+ (entries[i].mode & AE_IFMT) != AE_IFDIR) {
+ entries[i].mode &= ~AE_IFMT;
+ entries[i].mode |= AE_IFDIR;
+ }
+ if ((entries[i].mode & AE_IFMT) == AE_IFDIR &&
+ entries[i].name_len >= 2 &&
+ (entries[i].utf16name[entries[i].name_len-2] != '/' ||
+ entries[i].utf16name[entries[i].name_len-1] != 0)) {
+ entries[i].utf16name[entries[i].name_len] = '/';
+ entries[i].utf16name[entries[i].name_len+1] = 0;
+ entries[i].name_len += 2;
+ }
+ entries[i].ssIndex = -1;
+ }
+ if (entries[i].attr & 0x01)
+ entries[i].mode &= ~0222;/* Read only. */
+
+ if ((entries[i].flg & HAS_STREAM) == 0 && indexInFolder == 0) {
+ /*
+ * The entry is an empty file or a directory file,
+ * those both have no contents.
+ */
+ entries[i].folderIndex = -1;
+ continue;
+ }
+ if (indexInFolder == 0) {
+ for (;;) {
+ if (folderIndex >= si->ci.numFolders)
+ return (-1);
+ if (folders[folderIndex].numUnpackStreams)
+ break;
+ folderIndex++;
+ }
+ }
+ entries[i].folderIndex = folderIndex;
+ if ((entries[i].flg & HAS_STREAM) == 0)
+ continue;
+ indexInFolder++;
+ if (indexInFolder >= folders[folderIndex].numUnpackStreams) {
+ folderIndex++;
+ indexInFolder = 0;
+ }
+ }
+
+ return (0);
+}
+
+#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
+static void
+fileTimeToUtc(uint64_t fileTime, time_t *timep, long *ns)
+{
+
+ if (fileTime >= EPOC_TIME) {
+ fileTime -= EPOC_TIME;
+ /* milli seconds base */
+ *timep = (time_t)(fileTime / 10000000);
+ /* nano seconds base */
+ *ns = (long)(fileTime % 10000000) * 100;
+ } else {
+ *timep = 0;
+ *ns = 0;
+ }
+}
+
+static int
+read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ const unsigned char *p;
+ struct _7zip_entry *entries = zip->entries;
+ unsigned char *timeBools;
+ int allAreDefined;
+ unsigned i;
+
+ timeBools = calloc(zip->numFiles, sizeof(*timeBools));
+ if (timeBools == NULL)
+ return (-1);
+
+ /* Read allAreDefined. */
+ if ((p = header_bytes(a, 1)) == NULL)
+ goto failed;
+ allAreDefined = *p;
+ if (allAreDefined)
+ memset(timeBools, 1, zip->numFiles);
+ else {
+ if (read_Bools(a, timeBools, zip->numFiles) < 0)
+ goto failed;
+ }
+
+ /* Read external. */
+ if ((p = header_bytes(a, 1)) == NULL)
+ goto failed;
+ if (*p) {
+ if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
+ goto failed;
+ if (1000000 < h->dataIndex)
+ return (-1);
+ }
+
+ for (i = 0; i < zip->numFiles; i++) {
+ if (!timeBools[i])
+ continue;
+ if ((p = header_bytes(a, 8)) == NULL)
+ goto failed;
+ switch (type) {
+ case kCTime:
+ fileTimeToUtc(archive_le64dec(p),
+ &(entries[i].ctime),
+ &(entries[i].ctime_ns));
+ entries[i].flg |= CTIME_IS_SET;
+ break;
+ case kATime:
+ fileTimeToUtc(archive_le64dec(p),
+ &(entries[i].atime),
+ &(entries[i].atime_ns));
+ entries[i].flg |= ATIME_IS_SET;
+ break;
+ case kMTime:
+ fileTimeToUtc(archive_le64dec(p),
+ &(entries[i].mtime),
+ &(entries[i].mtime_ns));
+ entries[i].flg |= MTIME_IS_SET;
+ break;
+ }
+ }
+
+ free(timeBools);
+ return (0);
+failed:
+ free(timeBools);
+ return (-1);
+}
+
+static int
+decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+
+ errno = 0;
+ if (read_StreamsInfo(a, si) < 0) {
+ if (errno == ENOMEM)
+ archive_set_error(&a->archive, -1,
+ "Couldn't allocate memory");
+ else
+ archive_set_error(&a->archive, -1,
+ "Malformed 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (si->pi.numPackStreams == 0 || si->ci.numFolders == 0) {
+ archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (zip->header_offset < si->pi.pos + si->pi.sizes[0] ||
+ (int64_t)(si->pi.pos + si->pi.sizes[0]) < 0 ||
+ si->pi.sizes[0] == 0 || (int64_t)si->pi.pos < 0) {
+ archive_set_error(&a->archive, -1, "Malformed Header offset");
+ return (ARCHIVE_FATAL);
+ }
+
+ return (ARCHIVE_OK);
+}
+
+static const unsigned char *
+header_bytes(struct archive_read *a, size_t rbytes)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ const unsigned char *p;
+
+ if (zip->header_bytes_remaining < rbytes)
+ return (NULL);
+ if (zip->pack_stream_bytes_unconsumed)
+ read_consume(a);
+
+ if (zip->header_is_encoded == 0) {
+ p = __archive_read_ahead(a, rbytes, NULL);
+ if (p == NULL)
+ return (NULL);
+ zip->header_bytes_remaining -= rbytes;
+ zip->pack_stream_bytes_unconsumed = rbytes;
+ } else {
+ const void *buff;
+ ssize_t bytes;
+
+ bytes = read_stream(a, &buff, rbytes, rbytes);
+ if (bytes <= 0)
+ return (NULL);
+ zip->header_bytes_remaining -= bytes;
+ p = buff;
+ }
+
+ /* Update checksum */
+ zip->header_crc32 = crc32(zip->header_crc32, p, rbytes);
+ return (p);
+}
+
+static int
+slurp_central_directory(struct archive_read *a, struct _7zip *zip,
+ struct _7z_header_info *header)
+{
+ const unsigned char *p;
+ uint64_t next_header_offset;
+ uint64_t next_header_size;
+ uint32_t next_header_crc;
+ ssize_t bytes_avail;
+ int check_header_crc, r;
+
+ if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
+ return (ARCHIVE_FATAL);
+
+ if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
+ /* This is an executable ? Must be self-extracting... */
+ r = skip_sfx(a, bytes_avail);
+ if (r < ARCHIVE_WARN)
+ return (r);
+ if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ zip->seek_base += 32;
+
+ if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0) {
+ archive_set_error(&a->archive, -1, "Not 7-Zip archive file");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* CRC check. */
+ if (crc32(0, (const unsigned char *)p + 12, 20)
+ != archive_le32dec(p + 8)) {
+ archive_set_error(&a->archive, -1, "Header CRC error");
+ return (ARCHIVE_FATAL);
+ }
+
+ next_header_offset = archive_le64dec(p + 12);
+ next_header_size = archive_le64dec(p + 20);
+ next_header_crc = archive_le32dec(p + 28);
+
+ if (next_header_size == 0)
+ /* There is no entry in an archive file. */
+ return (ARCHIVE_EOF);
+
+ if (((int64_t)next_header_offset) < 0) {
+ archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
+ __archive_read_consume(a, 32);
+ if (next_header_offset != 0) {
+ if (bytes_avail >= (ssize_t)next_header_offset)
+ __archive_read_consume(a, next_header_offset);
+ else if (__archive_read_seek(a,
+ next_header_offset + zip->seek_base, SEEK_SET) < 0)
+ return (ARCHIVE_FATAL);
+ }
+ zip->stream_offset = next_header_offset;
+ zip->header_offset = next_header_offset;
+ zip->header_bytes_remaining = next_header_size;
+ zip->header_crc32 = 0;
+ zip->header_is_encoded = 0;
+ zip->header_is_being_read = 1;
+ check_header_crc = 1;
+
+ if ((p = header_bytes(a, 1)) == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated 7-Zip file body");
+ return (ARCHIVE_FATAL);
+ }
+ /* Parse ArchiveProperties. */
+ switch (p[0]) {
+ case kEncodedHeader:
+ /*
+ * The archive has an encoded header and we have to decode it
+ * in order to parse the header correctly.
+ */
+ r = decode_encoded_header_info(a, &(zip->si));
+
+ /* Check the EncodedHeader CRC.*/
+ if (r == 0 && zip->header_crc32 != next_header_crc) {
+ archive_set_error(&a->archive, -1,
+ "Damaged 7-Zip archive");
+ r = -1;
+ }
+ if (r == 0) {
+ if (zip->si.ci.folders[0].digest_defined)
+ next_header_crc = zip->si.ci.folders[0].digest;
+ else
+ check_header_crc = 0;
+ if (zip->pack_stream_bytes_unconsumed)
+ read_consume(a);
+ r = setup_decode_folder(a, zip->si.ci.folders, 1);
+ if (r == 0) {
+ zip->header_bytes_remaining =
+ zip->folder_outbytes_remaining;
+ r = seek_pack(a);
+ }
+ }
+ /* Clean up StreamsInfo. */
+ free_StreamsInfo(&(zip->si));
+ memset(&(zip->si), 0, sizeof(zip->si));
+ if (r < 0)
+ return (ARCHIVE_FATAL);
+ zip->header_is_encoded = 1;
+ zip->header_crc32 = 0;
+ /* FALL THROUGH */
+ case kHeader:
+ /*
+ * Parse the header.
+ */
+ errno = 0;
+ r = read_Header(a, header, zip->header_is_encoded);
+ if (r < 0) {
+ if (errno == ENOMEM)
+ archive_set_error(&a->archive, -1,
+ "Couldn't allocate memory");
+ else
+ archive_set_error(&a->archive, -1,
+ "Damaged 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
+
+ /*
+ * Must be kEnd.
+ */
+ if ((p = header_bytes(a, 1)) == NULL ||*p != kEnd) {
+ archive_set_error(&a->archive, -1,
+ "Malformed 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Check the Header CRC.*/
+ if (check_header_crc && zip->header_crc32 != next_header_crc) {
+ archive_set_error(&a->archive, -1,
+ "Malformed 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
+ break;
+ default:
+ archive_set_error(&a->archive, -1,
+ "Unexpected Property ID = %X", p[0]);
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Clean up variables be used for decoding the archive header */
+ zip->pack_stream_remaining = 0;
+ zip->pack_stream_index = 0;
+ zip->folder_outbytes_remaining = 0;
+ zip->uncompressed_buffer_bytes_remaining = 0;
+ zip->pack_stream_bytes_unconsumed = 0;
+ zip->header_is_being_read = 0;
+
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+get_uncompressed_data(struct archive_read *a, const void **buff, size_t size,
+ size_t minimum)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ ssize_t bytes_avail;
+
+ if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
+ /* Copy mode. */
+
+ /*
+ * Note: '1' here is a performance optimization.
+ * Recall that the decompression layer returns a count of
+ * available bytes; asking for more than that forces the
+ * decompressor to combine reads by copying data.
+ */
+ *buff = __archive_read_ahead(a, 1, &bytes_avail);
+ if (bytes_avail <= 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated 7-Zip file data");
+ return (ARCHIVE_FATAL);
+ }
+ if ((size_t)bytes_avail >
+ zip->uncompressed_buffer_bytes_remaining)
+ bytes_avail = (ssize_t)
+ zip->uncompressed_buffer_bytes_remaining;
+ if ((size_t)bytes_avail > size)
+ bytes_avail = (ssize_t)size;
+
+ zip->pack_stream_bytes_unconsumed = bytes_avail;
+ } else if (zip->uncompressed_buffer_pointer == NULL) {
+ /* Decompression has failed. */
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ } else {
+ /* Packed mode. */
+ if (minimum > zip->uncompressed_buffer_bytes_remaining) {
+ /*
+ * If remaining uncompressed data size is less than
+ * the minimum size, fill the buffer up to the
+ * minimum size.
+ */
+ if (extract_pack_stream(a, minimum) < 0)
+ return (ARCHIVE_FATAL);
+ }
+ if (size > zip->uncompressed_buffer_bytes_remaining)
+ bytes_avail = (ssize_t)
+ zip->uncompressed_buffer_bytes_remaining;
+ else
+ bytes_avail = (ssize_t)size;
+ *buff = zip->uncompressed_buffer_pointer;
+ zip->uncompressed_buffer_pointer += bytes_avail;
+ }
+ zip->uncompressed_buffer_bytes_remaining -= bytes_avail;
+ return (bytes_avail);
+}
+
+static ssize_t
+extract_pack_stream(struct archive_read *a, size_t minimum)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ ssize_t bytes_avail;
+ int r;
+
+ if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
+ if (minimum == 0)
+ minimum = 1;
+ if (__archive_read_ahead(a, minimum, &bytes_avail) == NULL
+ || bytes_avail <= 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated 7-Zip file body");
+ return (ARCHIVE_FATAL);
+ }
+ if (bytes_avail > (ssize_t)zip->pack_stream_inbytes_remaining)
+ bytes_avail = zip->pack_stream_inbytes_remaining;
+ zip->pack_stream_inbytes_remaining -= bytes_avail;
+ if (bytes_avail > (ssize_t)zip->folder_outbytes_remaining)
+ bytes_avail = zip->folder_outbytes_remaining;
+ zip->folder_outbytes_remaining -= bytes_avail;
+ zip->uncompressed_buffer_bytes_remaining = bytes_avail;
+ return (ARCHIVE_OK);
+ }
+
+ /* If the buffer hasn't been allocated, allocate it now. */
+ if (zip->uncompressed_buffer == NULL) {
+ zip->uncompressed_buffer_size = UBUFF_SIZE;
+ if (zip->uncompressed_buffer_size < minimum) {
+ zip->uncompressed_buffer_size = minimum + 1023;
+ zip->uncompressed_buffer_size &= ~0x3ff;
+ }
+ zip->uncompressed_buffer =
+ malloc(zip->uncompressed_buffer_size);
+ if (zip->uncompressed_buffer == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory for 7-Zip decompression");
+ return (ARCHIVE_FATAL);
+ }
+ zip->uncompressed_buffer_bytes_remaining = 0;
+ } else if (zip->uncompressed_buffer_size < minimum ||
+ zip->uncompressed_buffer_bytes_remaining < minimum) {
+ /*
+ * Make sure the uncompressed buffer can have bytes
+ * at least `minimum' bytes.
+ * NOTE: This case happen when reading the header.
+ */
+ size_t used;
+ if (zip->uncompressed_buffer_pointer != 0)
+ used = zip->uncompressed_buffer_pointer -
+ zip->uncompressed_buffer;
+ else
+ used = 0;
+ if (zip->uncompressed_buffer_size < minimum) {
+ /*
+ * Expand the uncompressed buffer up to
+ * the minimum size.
+ */
+ zip->uncompressed_buffer_size = minimum + 1023;
+ zip->uncompressed_buffer_size &= ~0x3ff;
+ zip->uncompressed_buffer =
+ realloc(zip->uncompressed_buffer,
+ zip->uncompressed_buffer_size);
+ if (zip->uncompressed_buffer == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory for 7-Zip decompression");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ /*
+ * Move unconsumed bytes to the head.
+ */
+ if (used) {
+ memmove(zip->uncompressed_buffer,
+ zip->uncompressed_buffer + used,
+ zip->uncompressed_buffer_bytes_remaining);
+ }
+ } else
+ zip->uncompressed_buffer_bytes_remaining = 0;
+ zip->uncompressed_buffer_pointer = NULL;
+ for (;;) {
+ size_t bytes_in, bytes_out;
+ const void *buff_in;
+ unsigned char *buff_out;
+ int eof;
+
+ /*
+ * Note: '1' here is a performance optimization.
+ * Recall that the decompression layer returns a count of
+ * available bytes; asking for more than that forces the
+ * decompressor to combine reads by copying data.
+ */
+ buff_in = __archive_read_ahead(a, 1, &bytes_avail);
+ if (bytes_avail <= 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated 7-Zip file body");
+ return (ARCHIVE_FATAL);
+ }
+
+ buff_out = zip->uncompressed_buffer
+ + zip->uncompressed_buffer_bytes_remaining;
+ bytes_out = zip->uncompressed_buffer_size
+ - zip->uncompressed_buffer_bytes_remaining;
+ bytes_in = bytes_avail;
+ if (bytes_in > zip->pack_stream_inbytes_remaining)
+ bytes_in = zip->pack_stream_inbytes_remaining;
+ /* Drive decompression. */
+ r = decompress(a, zip, buff_out, &bytes_out,
+ buff_in, &bytes_in);
+ switch (r) {
+ case ARCHIVE_OK:
+ eof = 0;
+ break;
+ case ARCHIVE_EOF:
+ eof = 1;
+ break;
+ default:
+ return (ARCHIVE_FATAL);
+ }
+ zip->pack_stream_inbytes_remaining -= bytes_in;
+ if (bytes_out > zip->folder_outbytes_remaining)
+ bytes_out = zip->folder_outbytes_remaining;
+ zip->folder_outbytes_remaining -= bytes_out;
+ zip->uncompressed_buffer_bytes_remaining += bytes_out;
+ zip->pack_stream_bytes_unconsumed = bytes_in;
+
+ /*
+ * Continue decompression until uncompressed_buffer is full.
+ */
+ if (zip->uncompressed_buffer_bytes_remaining ==
+ zip->uncompressed_buffer_size)
+ break;
+ if (zip->codec2 == _7Z_X86 && zip->odd_bcj_size &&
+ zip->uncompressed_buffer_bytes_remaining + 5 >
+ zip->uncompressed_buffer_size)
+ break;
+ if (zip->pack_stream_inbytes_remaining == 0 &&
+ zip->folder_outbytes_remaining == 0)
+ break;
+ if (eof || (bytes_in == 0 && bytes_out == 0)) {
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
+ read_consume(a);
+ }
+ if (zip->uncompressed_buffer_bytes_remaining < minimum) {
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
+ zip->uncompressed_buffer_pointer = zip->uncompressed_buffer;
+ return (ARCHIVE_OK);
+}
+
+static int
+seek_pack(struct archive_read *a)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ int64_t pack_offset;
+
+ if (zip->pack_stream_remaining <= 0) {
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
+ zip->pack_stream_inbytes_remaining =
+ zip->si.pi.sizes[zip->pack_stream_index];
+ pack_offset = zip->si.pi.positions[zip->pack_stream_index];
+ if (zip->stream_offset != pack_offset) {
+ if (0 > __archive_read_seek(a, pack_offset + zip->seek_base,
+ SEEK_SET))
+ return (ARCHIVE_FATAL);
+ zip->stream_offset = pack_offset;
+ }
+ zip->pack_stream_index++;
+ zip->pack_stream_remaining--;
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+read_stream(struct archive_read *a, const void **buff, size_t size,
+ size_t minimum)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ uint64_t skip_bytes = 0;
+ int r;
+
+ if (zip->uncompressed_buffer_bytes_remaining == 0) {
+ if (zip->pack_stream_inbytes_remaining > 0) {
+ r = extract_pack_stream(a, 0);
+ if (r < 0)
+ return (r);
+ return (get_uncompressed_data(a, buff, size, minimum));
+ } else if (zip->folder_outbytes_remaining > 0) {
+ /* Extract a remaining pack stream. */
+ r = extract_pack_stream(a, 0);
+ if (r < 0)
+ return (r);
+ return (get_uncompressed_data(a, buff, size, minimum));
+ }
+ } else
+ return (get_uncompressed_data(a, buff, size, minimum));
+
+ /*
+ * Current pack stream has been consumed.
+ */
+ if (zip->pack_stream_remaining == 0) {
+ if (zip->header_is_being_read) {
+ /* Invalid sequence. This might happen when
+ * reading a malformed archive. */
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC, "Malformed 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
+
+ /*
+ * All current folder's pack streams have been
+ * consumed. Switch to next folder.
+ */
+ if (zip->folder_index == 0 &&
+ (zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes
+ || zip->folder_index != zip->entry->folderIndex)) {
+ zip->folder_index = zip->entry->folderIndex;
+ skip_bytes =
+ zip->si.ci.folders[zip->folder_index].skipped_bytes;
+ }
+
+ if (zip->folder_index >= zip->si.ci.numFolders) {
+ /*
+ * We have consumed all folders and its pack streams.
+ */
+ *buff = NULL;
+ return (0);
+ }
+ r = setup_decode_folder(a,
+ &(zip->si.ci.folders[zip->folder_index]), 0);
+ if (r != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ zip->folder_index++;
+ }
+
+ /*
+ * Switch to next pack stream.
+ */
+ r = seek_pack(a);
+ if (r < 0)
+ return (r);
+
+ /* Extract a new pack stream. */
+ r = extract_pack_stream(a, 0);
+ if (r < 0)
+ return (r);
+
+ /*
+ * Skip the bytes we alrady has skipped in skip_stream().
+ */
+ while (skip_bytes) {
+ ssize_t skipped;
+
+ if (zip->uncompressed_buffer_bytes_remaining == 0) {
+ if (zip->pack_stream_inbytes_remaining > 0) {
+ r = extract_pack_stream(a, 0);
+ if (r < 0)
+ return (r);
+ } else if (zip->folder_outbytes_remaining > 0) {
+ /* Extract a remaining pack stream. */
+ r = extract_pack_stream(a, 0);
+ if (r < 0)
+ return (r);
+ } else {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated 7-Zip file body");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ skipped = get_uncompressed_data(a, buff, skip_bytes, 0);
+ if (skipped < 0)
+ return (skipped);
+ skip_bytes -= skipped;
+ if (zip->pack_stream_bytes_unconsumed)
+ read_consume(a);
+ }
+
+ return (get_uncompressed_data(a, buff, size, minimum));
+}
+
+static int
+setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
+ int header)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ const struct _7z_coder *coder1, *coder2;
+ const char *cname = (header)?"archive header":"file content";
+ unsigned i;
+ int r, found_bcj2 = 0;
+
+ /*
+ * Release the memory which the previous folder used for BCJ2.
+ */
+ for (i = 0; i < 3; i++) {
+ if (zip->sub_stream_buff[i] != NULL)
+ free(zip->sub_stream_buff[i]);
+ zip->sub_stream_buff[i] = NULL;
+ }
+
+ /*
+ * Initialize a stream reader.
+ */
+ zip->pack_stream_remaining = (unsigned)folder->numPackedStreams;
+ zip->pack_stream_index = (unsigned)folder->packIndex;
+ zip->folder_outbytes_remaining = folder_uncompressed_size(folder);
+ zip->uncompressed_buffer_bytes_remaining = 0;
+
+ /*
+ * Check coder types.
+ */
+ for (i = 0; i < folder->numCoders; i++) {
+ if (folder->coders[i].codec == _7Z_CRYPTO) {
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "The %s is encrypted, "
+ "but currently not supported", cname);
+ return (ARCHIVE_FATAL);
+ }
+ if (folder->coders[i].codec == _7Z_X86_BCJ2)
+ found_bcj2++;
+ }
+ if ((folder->numCoders > 2 && !found_bcj2) || found_bcj2 > 1) {
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "The %s is encoded with many filters, "
+ "but currently not supported", cname);
+ return (ARCHIVE_FATAL);
+ }
+ coder1 = &(folder->coders[0]);
+ if (folder->numCoders == 2)
+ coder2 = &(folder->coders[1]);
+ else
+ coder2 = NULL;
+
+ if (found_bcj2) {
+ /*
+ * Preparation to decode BCJ2.
+ * Decoding BCJ2 requires four sources. Those are at least,
+ * as far as I know, two types of the storage form.
+ */
+ const struct _7z_coder *fc = folder->coders;
+ static const struct _7z_coder coder_copy = {0, 1, 1, 0, NULL};
+ const struct _7z_coder *scoder[3] =
+ {&coder_copy, &coder_copy, &coder_copy};
+ const void *buff;
+ ssize_t bytes;
+ unsigned char *b[3] = {NULL, NULL, NULL};
+ uint64_t sunpack[3] ={-1, -1, -1};
+ size_t s[3] = {0, 0, 0};
+ int idx[3] = {0, 1, 2};
+
+ if (folder->numCoders == 4 && fc[3].codec == _7Z_X86_BCJ2 &&
+ folder->numInStreams == 7 && folder->numOutStreams == 4 &&
+ zip->pack_stream_remaining == 4) {
+ /* Source type 1 made by 7zr or 7z with -m options. */
+ if (folder->bindPairs[0].inIndex == 5) {
+ /* The form made by 7zr */
+ idx[0] = 1; idx[1] = 2; idx[2] = 0;
+ scoder[1] = &(fc[1]);
+ scoder[2] = &(fc[0]);
+ sunpack[1] = folder->unPackSize[1];
+ sunpack[2] = folder->unPackSize[0];
+ coder1 = &(fc[2]);
+ } else {
+ /*
+ * NOTE: Some patterns do not work.
+ * work:
+ * 7z a -m0=BCJ2 -m1=COPY -m2=COPY
+ * -m3=(any)
+ * 7z a -m0=BCJ2 -m1=COPY -m2=(any)
+ * -m3=COPY
+ * 7z a -m0=BCJ2 -m1=(any) -m2=COPY
+ * -m3=COPY
+ * not work:
+ * other patterns.
+ *
+ * We have to handle this like `pipe' or
+ * our libarchive7s filter frame work,
+ * decoding the BCJ2 main stream sequentially,
+ * m3 -> m2 -> m1 -> BCJ2.
+ *
+ */
+ if (fc[0].codec == _7Z_COPY &&
+ fc[1].codec == _7Z_COPY)
+ coder1 = &(folder->coders[2]);
+ else if (fc[0].codec == _7Z_COPY &&
+ fc[2].codec == _7Z_COPY)
+ coder1 = &(folder->coders[1]);
+ else if (fc[1].codec == _7Z_COPY &&
+ fc[2].codec == _7Z_COPY)
+ coder1 = &(folder->coders[0]);
+ else {
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Unsupported form of "
+ "BCJ2 streams");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ coder2 = &(fc[3]);
+ zip->main_stream_bytes_remaining =
+ folder->unPackSize[2];
+ } else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 &&
+ zip->pack_stream_remaining == 4 &&
+ folder->numInStreams == 5 && folder->numOutStreams == 2) {
+ /* Source type 0 made by 7z */
+ zip->main_stream_bytes_remaining =
+ folder->unPackSize[0];
+ } else {
+ /* We got an unexpected form. */
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Unsupported form of BCJ2 streams");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Skip the main stream at this time. */
+ if ((r = seek_pack(a)) < 0)
+ return (r);
+ zip->pack_stream_bytes_unconsumed =
+ zip->pack_stream_inbytes_remaining;
+ read_consume(a);
+
+ /* Read following three sub streams. */
+ for (i = 0; i < 3; i++) {
+ const struct _7z_coder *coder = scoder[i];
+
+ if ((r = seek_pack(a)) < 0)
+ return (r);
+
+ if (sunpack[i] == (uint64_t)-1)
+ zip->folder_outbytes_remaining =
+ zip->pack_stream_inbytes_remaining;
+ else
+ zip->folder_outbytes_remaining = sunpack[i];
+
+ r = init_decompression(a, zip, coder, NULL);
+ if (r != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ /* Allocate memory for the decorded data of a sub
+ * stream. */
+ b[i] = malloc(zip->folder_outbytes_remaining);
+ if (b[i] == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory for 7-Zip decompression");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Extract a sub stream. */
+ while (zip->pack_stream_inbytes_remaining > 0) {
+ r = extract_pack_stream(a, 0);
+ if (r < 0)
+ return (r);
+ bytes = get_uncompressed_data(a, &buff,
+ zip->uncompressed_buffer_bytes_remaining,
+ 0);
+ if (bytes < 0)
+ return ((int)bytes);
+ memcpy(b[i]+s[i], buff, bytes);
+ s[i] += bytes;
+ if (zip->pack_stream_bytes_unconsumed)
+ read_consume(a);
+ }
+ }
+
+ /* Set the sub streams to the right place. */
+ for (i = 0; i < 3; i++) {
+ zip->sub_stream_buff[i] = b[idx[i]];
+ zip->sub_stream_size[i] = s[idx[i]];
+ zip->sub_stream_bytes_remaining[i] = s[idx[i]];
+ }
+
+ /* Allocate memory used for decoded main stream bytes. */
+ if (zip->tmp_stream_buff == NULL) {
+ zip->tmp_stream_buff_size = 32 * 1024;
+ zip->tmp_stream_buff =
+ malloc(zip->tmp_stream_buff_size);
+ if (zip->tmp_stream_buff == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory for 7-Zip decompression");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ zip->tmp_stream_bytes_avail = 0;
+ zip->tmp_stream_bytes_remaining = 0;
+ zip->odd_bcj_size = 0;
+ zip->bcj2_outPos = 0;
+
+ /*
+ * Reset a stream reader in order to read the main stream
+ * of BCJ2.
+ */
+ zip->pack_stream_remaining = 1;
+ zip->pack_stream_index = (unsigned)folder->packIndex;
+ zip->folder_outbytes_remaining =
+ folder_uncompressed_size(folder);
+ zip->uncompressed_buffer_bytes_remaining = 0;
+ }
+
+ /*
+ * Initialize the decompressor for the new folder's pack streams.
+ */
+ r = init_decompression(a, zip, coder1, coder2);
+ if (r != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ return (ARCHIVE_OK);
+}
+
+static int64_t
+skip_stream(struct archive_read *a, size_t skip_bytes)
+{
+ struct _7zip *zip = (struct _7zip *)a->format->data;
+ const void *p;
+ int64_t skipped_bytes;
+ size_t bytes = skip_bytes;
+
+ if (zip->folder_index == 0) {
+ /*
+ * Optimization for a list mode.
+ * Avoid unncecessary decoding operations.
+ */
+ zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes
+ += skip_bytes;
+ return (skip_bytes);
+ }
+
+ while (bytes) {
+ skipped_bytes = read_stream(a, &p, bytes, 0);
+ if (skipped_bytes < 0)
+ return (skipped_bytes);
+ if (skipped_bytes == 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated 7-Zip file body");
+ return (ARCHIVE_FATAL);
+ }
+ bytes -= skipped_bytes;
+ if (zip->pack_stream_bytes_unconsumed)
+ read_consume(a);
+ }
+ return (skip_bytes);
+}
+
+/*
+ * Brought from LZMA SDK.
+ *
+ * Bra86.c -- Converter for x86 code (BCJ)
+ * 2008-10-04 : Igor Pavlov : Public domain
+ *
+ */
+
+#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
+
+static void
+x86_Init(struct _7zip *zip)
+{
+ zip->bcj_state = 0;
+ zip->bcj_prevPosT = (size_t)0 - 1;
+ zip->bcj_prevMask = 0;
+ zip->bcj_ip = 5;
+}
+
+static size_t
+x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
+{
+ static const uint8_t kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
+ static const uint8_t kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
+ size_t bufferPos, prevPosT;
+ uint32_t ip, prevMask;
+
+ if (size < 5)
+ return 0;
+
+ bufferPos = 0;
+ prevPosT = zip->bcj_prevPosT;
+ prevMask = zip->bcj_prevMask;
+ ip = zip->bcj_ip;
+
+ for (;;) {
+ uint8_t *p = data + bufferPos;
+ uint8_t *limit = data + size - 4;
+
+ for (; p < limit; p++)
+ if ((*p & 0xFE) == 0xE8)
+ break;
+ bufferPos = (size_t)(p - data);
+ if (p >= limit)
+ break;
+ prevPosT = bufferPos - prevPosT;
+ if (prevPosT > 3)
+ prevMask = 0;
+ else {
+ prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
+ if (prevMask != 0) {
+ unsigned char b =
+ p[4 - kMaskToBitNumber[prevMask]];
+ if (!kMaskToAllowedStatus[prevMask] ||
+ Test86MSByte(b)) {
+ prevPosT = bufferPos;
+ prevMask = ((prevMask << 1) & 0x7) | 1;
+ bufferPos++;
+ continue;
+ }
+ }
+ }
+ prevPosT = bufferPos;
+
+ if (Test86MSByte(p[4])) {
+ uint32_t src = ((uint32_t)p[4] << 24) |
+ ((uint32_t)p[3] << 16) | ((uint32_t)p[2] << 8) |
+ ((uint32_t)p[1]);
+ uint32_t dest;
+ for (;;) {
+ uint8_t b;
+ int b_index;
+
+ dest = src - (ip + (uint32_t)bufferPos);
+ if (prevMask == 0)
+ break;
+ b_index = kMaskToBitNumber[prevMask] * 8;
+ b = (uint8_t)(dest >> (24 - b_index));
+ if (!Test86MSByte(b))
+ break;
+ src = dest ^ ((1 << (32 - b_index)) - 1);
+ }
+ p[4] = (uint8_t)(~(((dest >> 24) & 1) - 1));
+ p[3] = (uint8_t)(dest >> 16);
+ p[2] = (uint8_t)(dest >> 8);
+ p[1] = (uint8_t)dest;
+ bufferPos += 5;
+ } else {
+ prevMask = ((prevMask << 1) & 0x7) | 1;
+ bufferPos++;
+ }
+ }
+ zip->bcj_prevPosT = prevPosT;
+ zip->bcj_prevMask = prevMask;
+ zip->bcj_ip += bufferPos;
+ return (bufferPos);
+}
+
+/*
+ * Brought from LZMA SDK.
+ *
+ * Bcj2.c -- Converter for x86 code (BCJ2)
+ * 2008-10-04 : Igor Pavlov : Public domain
+ *
+ */
+
+#define SZ_ERROR_DATA ARCHIVE_FAILED
+
+#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)
+#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))
+
+#define kNumTopBits 24
+#define kTopValue ((uint32_t)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*buffer++)
+#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
+#define RC_INIT2 zip->bcj2_code = 0; zip->bcj2_range = 0xFFFFFFFF; \
+ { int ii; for (ii = 0; ii < 5; ii++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
+
+#define NORMALIZE if (zip->bcj2_range < kTopValue) { RC_TEST; zip->bcj2_range <<= 8; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }
+
+#define IF_BIT_0(p) ttt = *(p); bound = (zip->bcj2_range >> kNumBitModelTotalBits) * ttt; if (zip->bcj2_code < bound)
+#define UPDATE_0(p) zip->bcj2_range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE;
+#define UPDATE_1(p) zip->bcj2_range -= bound; zip->bcj2_code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE;
+
+static ssize_t
+Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
+{
+ size_t inPos = 0, outPos = 0;
+ const uint8_t *buf0, *buf1, *buf2, *buf3;
+ size_t size0, size1, size2, size3;
+ const uint8_t *buffer, *bufferLim;
+ unsigned int i, j;
+
+ size0 = zip->tmp_stream_bytes_remaining;
+ buf0 = zip->tmp_stream_buff + zip->tmp_stream_bytes_avail - size0;
+ size1 = zip->sub_stream_bytes_remaining[0];
+ buf1 = zip->sub_stream_buff[0] + zip->sub_stream_size[0] - size1;
+ size2 = zip->sub_stream_bytes_remaining[1];
+ buf2 = zip->sub_stream_buff[1] + zip->sub_stream_size[1] - size2;
+ size3 = zip->sub_stream_bytes_remaining[2];
+ buf3 = zip->sub_stream_buff[2] + zip->sub_stream_size[2] - size3;
+
+ buffer = buf3;
+ bufferLim = buffer + size3;
+
+ if (zip->bcj_state == 0) {
+ /*
+ * Initialize.
+ */
+ zip->bcj2_prevByte = 0;
+ for (i = 0;
+ i < sizeof(zip->bcj2_p) / sizeof(zip->bcj2_p[0]); i++)
+ zip->bcj2_p[i] = kBitModelTotal >> 1;
+ RC_INIT2;
+ zip->bcj_state = 1;
+ }
+
+ /*
+ * Gather the odd bytes of a previous call.
+ */
+ for (i = 0; zip->odd_bcj_size > 0 && outPos < outSize; i++) {
+ outBuf[outPos++] = zip->odd_bcj[i];
+ zip->odd_bcj_size--;
+ }
+
+ if (outSize == 0) {
+ zip->bcj2_outPos += outPos;
+ return (outPos);
+ }
+
+ for (;;) {
+ uint8_t b;
+ CProb *prob;
+ uint32_t bound;
+ uint32_t ttt;
+
+ size_t limit = size0 - inPos;
+ if (outSize - outPos < limit)
+ limit = outSize - outPos;
+
+ if (zip->bcj_state == 1) {
+ while (limit != 0) {
+ uint8_t bb = buf0[inPos];
+ outBuf[outPos++] = bb;
+ if (IsJ(zip->bcj2_prevByte, bb)) {
+ zip->bcj_state = 2;
+ break;
+ }
+ inPos++;
+ zip->bcj2_prevByte = bb;
+ limit--;
+ }
+ }
+
+ if (limit == 0 || outPos == outSize)
+ break;
+ zip->bcj_state = 1;
+
+ b = buf0[inPos++];
+
+ if (b == 0xE8)
+ prob = zip->bcj2_p + zip->bcj2_prevByte;
+ else if (b == 0xE9)
+ prob = zip->bcj2_p + 256;
+ else
+ prob = zip->bcj2_p + 257;
+
+ IF_BIT_0(prob) {
+ UPDATE_0(prob)
+ zip->bcj2_prevByte = b;
+ } else {
+ uint32_t dest;
+ const uint8_t *v;
+ uint8_t out[4];
+
+ UPDATE_1(prob)
+ if (b == 0xE8) {
+ v = buf1;
+ if (size1 < 4)
+ return SZ_ERROR_DATA;
+ buf1 += 4;
+ size1 -= 4;
+ } else {
+ v = buf2;
+ if (size2 < 4)
+ return SZ_ERROR_DATA;
+ buf2 += 4;
+ size2 -= 4;
+ }
+ dest = (((uint32_t)v[0] << 24) |
+ ((uint32_t)v[1] << 16) |
+ ((uint32_t)v[2] << 8) |
+ ((uint32_t)v[3])) -
+ ((uint32_t)zip->bcj2_outPos + outPos + 4);
+ out[0] = (uint8_t)dest;
+ out[1] = (uint8_t)(dest >> 8);
+ out[2] = (uint8_t)(dest >> 16);
+ out[3] = zip->bcj2_prevByte = (uint8_t)(dest >> 24);
+
+ for (i = 0; i < 4 && outPos < outSize; i++)
+ outBuf[outPos++] = out[i];
+ if (i < 4) {
+ /*
+ * Save odd bytes which we could not add into
+ * the output buffer because of out of space.
+ */
+ zip->odd_bcj_size = 4 -i;
+ for (; i < 4; i++) {
+ j = i - 4 + zip->odd_bcj_size;
+ zip->odd_bcj[j] = out[i];
+ }
+ break;
+ }
+ }
+ }
+ zip->tmp_stream_bytes_remaining -= inPos;
+ zip->sub_stream_bytes_remaining[0] = size1;
+ zip->sub_stream_bytes_remaining[1] = size2;
+ zip->sub_stream_bytes_remaining[2] = bufferLim - buffer;
+ zip->bcj2_outPos += outPos;
+
+ return ((ssize_t)outPos);
+}
+
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_format_by_code.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_format_by_code.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2003-2011 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive.h"
+#include "archive_private.h"
+
+int
+archive_read_support_format_by_code(struct archive *a, int format_code)
+{
+ archive_check_magic(a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_format_by_code");
+
+ switch (format_code & ARCHIVE_FORMAT_BASE_MASK) {
+ case ARCHIVE_FORMAT_7ZIP:
+ return archive_read_support_format_7zip(a);
+ break;
+ case ARCHIVE_FORMAT_AR:
+ return archive_read_support_format_ar(a);
+ break;
+ case ARCHIVE_FORMAT_CAB:
+ return archive_read_support_format_cab(a);
+ break;
+ case ARCHIVE_FORMAT_CPIO:
+ return archive_read_support_format_cpio(a);
+ break;
+ case ARCHIVE_FORMAT_ISO9660:
+ return archive_read_support_format_iso9660(a);
+ break;
+ case ARCHIVE_FORMAT_LHA:
+ return archive_read_support_format_lha(a);
+ break;
+ case ARCHIVE_FORMAT_MTREE:
+ return archive_read_support_format_mtree(a);
+ break;
+ case ARCHIVE_FORMAT_RAR:
+ return archive_read_support_format_rar(a);
+ break;
+ case ARCHIVE_FORMAT_TAR:
+ return archive_read_support_format_tar(a);
+ break;
+ case ARCHIVE_FORMAT_XAR:
+ return archive_read_support_format_xar(a);
+ break;
+ case ARCHIVE_FORMAT_ZIP:
+ return archive_read_support_format_zip(a);
+ break;
+ }
+ return (ARCHIVE_FATAL);
+}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_format_cab.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_format_cab.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,3323 @@
+/*-
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_entry_locale.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+#include "archive_endian.h"
+
+
+struct lzx_dec {
+ /* Decoding status. */
+ int state;
+
+ /*
+ * Window to see last decoded data, from 32KBi to 2MBi.
+ */
+ int w_size;
+ int w_mask;
+ /* Window buffer, which is a loop buffer. */
+ unsigned char *w_buff;
+ /* The insert position to the window. */
+ int w_pos;
+ /* The position where we can copy decoded code from the window. */
+ int copy_pos;
+ /* The length how many bytes we can copy decoded code from
+ * the window. */
+ int copy_len;
+ /* Translation reversal for x86 proccessor CALL byte sequence(E8).
+ * This is used for LZX only. */
+ uint32_t translation_size;
+ char translation;
+ char block_type;
+#define VERBATIM_BLOCK 1
+#define ALIGNED_OFFSET_BLOCK 2
+#define UNCOMPRESSED_BLOCK 3
+ size_t block_size;
+ size_t block_bytes_avail;
+ /* Repeated offset. */
+ int r0, r1, r2;
+ unsigned char rbytes[4];
+ int rbytes_avail;
+ int length_header;
+ int position_slot;
+ int offset_bits;
+
+ struct lzx_pos_tbl {
+ int base;
+ int footer_bits;
+ } *pos_tbl;
+ /*
+ * Bit stream reader.
+ */
+ struct lzx_br {
+#define CACHE_TYPE uint64_t
+#define CACHE_BITS (8 * sizeof(CACHE_TYPE))
+ /* Cache buffer. */
+ CACHE_TYPE cache_buffer;
+ /* Indicates how many bits avail in cache_buffer. */
+ int cache_avail;
+ unsigned char odd;
+ char have_odd;
+ } br;
+
+ /*
+ * Huffman coding.
+ */
+ struct huffman {
+ int len_size;
+ int freq[17];
+ unsigned char *bitlen;
+
+ /*
+ * Use a index table. It's faster than searching a huffman
+ * coding tree, which is a binary tree. But a use of a large
+ * index table causes L1 cache read miss many times.
+ */
+#define HTBL_BITS 10
+ int max_bits;
+ int shift_bits;
+ int tbl_bits;
+ int tree_used;
+ int tree_avail;
+ /* Direct access table. */
+ uint16_t *tbl;
+ /* Binary tree table for extra bits over the direct access. */
+ struct htree_t {
+ uint16_t left;
+ uint16_t right;
+ } *tree;
+ } at, lt, mt, pt;
+
+ int loop;
+ int error;
+};
+
+static const int slots[] = {
+ 30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
+};
+#define SLOT_BASE 15
+#define SLOT_MAX 21/*->25*/
+
+struct lzx_stream {
+ const unsigned char *next_in;
+ int64_t avail_in;
+ int64_t total_in;
+ unsigned char *next_out;
+ int64_t avail_out;
+ int64_t total_out;
+ struct lzx_dec *ds;
+};
+
+/*
+ * Cabinet file definitions.
+ */
+/* CFHEADER offset */
+#define CFHEADER_signature 0
+#define CFHEADER_cbCabinet 8
+#define CFHEADER_coffFiles 16
+#define CFHEADER_versionMinor 24
+#define CFHEADER_versionMajor 25
+#define CFHEADER_cFolders 26
+#define CFHEADER_cFiles 28
+#define CFHEADER_flags 30
+#define CFHEADER_setID 32
+#define CFHEADER_iCabinet 34
+#define CFHEADER_cbCFHeader 36
+#define CFHEADER_cbCFFolder 38
+#define CFHEADER_cbCFData 39
+
+/* CFFOLDER offset */
+#define CFFOLDER_coffCabStart 0
+#define CFFOLDER_cCFData 4
+#define CFFOLDER_typeCompress 6
+#define CFFOLDER_abReserve 8
+
+/* CFFILE offset */
+#define CFFILE_cbFile 0
+#define CFFILE_uoffFolderStart 4
+#define CFFILE_iFolder 8
+#define CFFILE_date_time 10
+#define CFFILE_attribs 14
+
+/* CFDATA offset */
+#define CFDATA_csum 0
+#define CFDATA_cbData 4
+#define CFDATA_cbUncomp 6
+
+static const char *compression_name[] = {
+ "NONE",
+ "MSZIP",
+ "Quantum",
+ "LZX",
+};
+
+struct cfdata {
+ /* Sum value of this CFDATA. */
+ uint32_t sum;
+ uint16_t compressed_size;
+ uint16_t compressed_bytes_remaining;
+ uint16_t uncompressed_size;
+ uint16_t uncompressed_bytes_remaining;
+ /* To know how many bytes we have decompressed. */
+ uint16_t uncompressed_avail;
+ /* Offset from the beginning of compressed data of this CFDATA */
+ uint16_t read_offset;
+ int64_t unconsumed;
+ /* To keep memory image of this CFDATA to compute the sum. */
+ size_t memimage_size;
+ unsigned char *memimage;
+ /* Result of calculation of sum. */
+ uint32_t sum_calculated;
+ unsigned char sum_extra[4];
+ int sum_extra_avail;
+ const void *sum_ptr;
+};
+
+struct cffolder {
+ uint32_t cfdata_offset_in_cab;
+ uint16_t cfdata_count;
+ uint16_t comptype;
+#define COMPTYPE_NONE 0x0000
+#define COMPTYPE_MSZIP 0x0001
+#define COMPTYPE_QUANTUM 0x0002
+#define COMPTYPE_LZX 0x0003
+ uint16_t compdata;
+ const char *compname;
+ /* At the time reading CFDATA */
+ struct cfdata cfdata;
+ int cfdata_index;
+ /* Flags to mark progress of decompression. */
+ char decompress_init;
+};
+
+struct cffile {
+ uint32_t uncompressed_size;
+ uint32_t offset;
+ time_t mtime;
+ uint16_t folder;
+#define iFoldCONTINUED_FROM_PREV 0xFFFD
+#define iFoldCONTINUED_TO_NEXT 0xFFFE
+#define iFoldCONTINUED_PREV_AND_NEXT 0xFFFF
+ unsigned char attr;
+#define ATTR_RDONLY 0x01
+#define ATTR_NAME_IS_UTF 0x80
+ struct archive_string pathname;
+};
+
+struct cfheader {
+ /* Total bytes of all file size in a Cabinet. */
+ uint32_t total_bytes;
+ uint32_t files_offset;
+ uint16_t folder_count;
+ uint16_t file_count;
+ uint16_t flags;
+#define PREV_CABINET 0x0001
+#define NEXT_CABINET 0x0002
+#define RESERVE_PRESENT 0x0004
+ uint16_t setid;
+ uint16_t cabinet;
+ /* Version number. */
+ unsigned char major;
+ unsigned char minor;
+ unsigned char cffolder;
+ unsigned char cfdata;
+ /* All folders in a cabinet. */
+ struct cffolder *folder_array;
+ /* All files in a cabinet. */
+ struct cffile *file_array;
+ int file_index;
+};
+
+struct cab {
+ /* entry_bytes_remaining is the number of bytes we expect. */
+ int64_t entry_offset;
+ int64_t entry_bytes_remaining;
+ int64_t entry_unconsumed;
+ int64_t entry_compressed_bytes_read;
+ int64_t entry_uncompressed_bytes_read;
+ struct cffolder *entry_cffolder;
+ struct cffile *entry_cffile;
+ struct cfdata *entry_cfdata;
+
+ /* Offset from beginning of a cabinet file. */
+ int64_t cab_offset;
+ struct cfheader cfheader;
+ struct archive_wstring ws;
+
+ /* Flag to mark progress that an archive was read their first header.*/
+ char found_header;
+ char end_of_archive;
+ char end_of_entry;
+ char end_of_entry_cleanup;
+
+ unsigned char *uncompressed_buffer;
+ size_t uncompressed_buffer_size;
+
+ int init_default_conversion;
+ struct archive_string_conv *sconv;
+ struct archive_string_conv *sconv_default;
+ struct archive_string_conv *sconv_utf8;
+ char format_name[64];
+
+#ifdef HAVE_ZLIB_H
+ z_stream stream;
+ char stream_valid;
+#endif
+ struct lzx_stream xstrm;
+};
+
+static int archive_read_format_cab_bid(struct archive_read *, int);
+static int archive_read_format_cab_options(struct archive_read *,
+ const char *, const char *);
+static int archive_read_format_cab_read_header(struct archive_read *,
+ struct archive_entry *);
+static int archive_read_format_cab_read_data(struct archive_read *,
+ const void **, size_t *, int64_t *);
+static int archive_read_format_cab_read_data_skip(struct archive_read *);
+static int archive_read_format_cab_cleanup(struct archive_read *);
+
+static int cab_skip_sfx(struct archive_read *);
+static time_t cab_dos_time(const unsigned char *);
+static int cab_read_data(struct archive_read *, const void **,
+ size_t *, int64_t *);
+static int cab_read_header(struct archive_read *);
+static uint32_t cab_checksum_cfdata_4(const void *, size_t bytes, uint32_t);
+static uint32_t cab_checksum_cfdata(const void *, size_t bytes, uint32_t);
+static void cab_checksum_update(struct archive_read *, size_t);
+static int cab_checksum_finish(struct archive_read *);
+static int cab_next_cfdata(struct archive_read *);
+static const void *cab_read_ahead_cfdata(struct archive_read *, ssize_t *);
+static const void *cab_read_ahead_cfdata_none(struct archive_read *, ssize_t *);
+static const void *cab_read_ahead_cfdata_deflate(struct archive_read *,
+ ssize_t *);
+static const void *cab_read_ahead_cfdata_lzx(struct archive_read *,
+ ssize_t *);
+static int64_t cab_consume_cfdata(struct archive_read *, int64_t);
+static int64_t cab_minimum_consume_cfdata(struct archive_read *, int64_t);
+static int lzx_decode_init(struct lzx_stream *, int);
+static int lzx_read_blocks(struct lzx_stream *, int);
+static int lzx_decode_blocks(struct lzx_stream *, int);
+static void lzx_decode_free(struct lzx_stream *);
+static void lzx_translation(struct lzx_stream *, void *, size_t, uint32_t);
+static void lzx_cleanup_bitstream(struct lzx_stream *);
+static int lzx_decode(struct lzx_stream *, int);
+static int lzx_read_pre_tree(struct lzx_stream *);
+static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);
+static int lzx_huffman_init(struct huffman *, size_t, int);
+static void lzx_huffman_free(struct huffman *);
+static int lzx_make_huffman_table(struct huffman *);
+static inline int lzx_decode_huffman(struct huffman *, unsigned);
+static int lzx_decode_huffman_tree(struct huffman *, unsigned, int);
+
+
+int
+archive_read_support_format_cab(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct cab *cab;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_format_cab");
+
+ cab = (struct cab *)calloc(1, sizeof(*cab));
+ if (cab == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate CAB data");
+ return (ARCHIVE_FATAL);
+ }
+ archive_string_init(&cab->ws);
+ archive_wstring_ensure(&cab->ws, 256);
+
+ r = __archive_read_register_format(a,
+ cab,
+ "cab",
+ archive_read_format_cab_bid,
+ archive_read_format_cab_options,
+ archive_read_format_cab_read_header,
+ archive_read_format_cab_read_data,
+ archive_read_format_cab_read_data_skip,
+ archive_read_format_cab_cleanup);
+
+ if (r != ARCHIVE_OK)
+ free(cab);
+ return (ARCHIVE_OK);
+}
+
+static int
+find_cab_magic(const char *p)
+{
+ switch (p[4]) {
+ case 0:
+ /*
+ * Note: Self-Extraction program has 'MSCF' string in their
+ * program. If we were finding 'MSCF' string only, we got
+ * wrong place for Cabinet header, thus, we have to check
+ * following four bytes which are reserved and must be set
+ * to zero.
+ */
+ if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)
+ return 0;
+ return 5;
+ case 'F': return 1;
+ case 'C': return 2;
+ case 'S': return 3;
+ case 'M': return 4;
+ default: return 5;
+ }
+}
+
+static int
+archive_read_format_cab_bid(struct archive_read *a, int best_bid)
+{
+ const char *p;
+ ssize_t bytes_avail, offset, window;
+
+ /* If there's already a better bid than we can ever
+ make, don't bother testing. */
+ if (best_bid > 64)
+ return (-1);
+
+ if ((p = __archive_read_ahead(a, 8, NULL)) == NULL)
+ return (-1);
+
+ if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)
+ return (64);
+
+ /*
+ * Attempt to handle self-extracting archives
+ * by noting a PE header and searching forward
+ * up to 128k for a 'MSCF' marker.
+ */
+ if (p[0] == 'M' && p[1] == 'Z') {
+ offset = 0;
+ window = 4096;
+ while (offset < (1024 * 128)) {
+ const char *h = __archive_read_ahead(a, offset + window,
+ &bytes_avail);
+ if (h == NULL) {
+ /* Remaining bytes are less than window. */
+ window >>= 1;
+ if (window < 128)
+ return (0);
+ continue;
+ }
+ p = h + offset;
+ while (p + 8 < h + bytes_avail) {
+ int next;
+ if ((next = find_cab_magic(p)) == 0)
+ return (64);
+ p += next;
+ }
+ offset = p - h;
+ }
+ }
+ return (0);
+}
+
+static int
+archive_read_format_cab_options(struct archive_read *a,
+ const char *key, const char *val)
+{
+ struct cab *cab;
+ int ret = ARCHIVE_FAILED;
+
+ cab = (struct cab *)(a->format->data);
+ if (strcmp(key, "hdrcharset") == 0) {
+ if (val == NULL || val[0] == 0)
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "cab: hdrcharset option needs a character-set name");
+ else {
+ cab->sconv = archive_string_conversion_from_charset(
+ &a->archive, val, 0);
+ if (cab->sconv != NULL)
+ ret = ARCHIVE_OK;
+ else
+ ret = ARCHIVE_FATAL;
+ }
+ return (ret);
+ }
+
+ /* Note: The "warn" return is just to inform the options
+ * supervisor that we didn't handle it. It will generate
+ * a suitable error if no one used this option. */
+ return (ARCHIVE_WARN);
+}
+
+static int
+cab_skip_sfx(struct archive_read *a)
+{
+ const char *p, *q;
+ size_t skip;
+ ssize_t bytes, window;
+
+ window = 4096;
+ for (;;) {
+ const char *h = __archive_read_ahead(a, window, &bytes);
+ if (h == NULL) {
+ /* Remaining size are less than window. */
+ window >>= 1;
+ if (window < 128) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Couldn't find out CAB header");
+ return (ARCHIVE_FATAL);
+ }
+ continue;
+ }
+ p = h;
+ q = p + bytes;
+
+ /*
+ * Scan ahead until we find something that looks
+ * like the cab header.
+ */
+ while (p + 8 < q) {
+ int next;
+ if ((next = find_cab_magic(p)) == 0) {
+ skip = p - h;
+ __archive_read_consume(a, skip);
+ return (ARCHIVE_OK);
+ }
+ p += next;
+ }
+ skip = p - h;
+ __archive_read_consume(a, skip);
+ }
+}
+
+static int
+truncated_error(struct archive_read *a)
+{
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated CAB header");
+ return (ARCHIVE_FATAL);
+}
+
+static int
+cab_strnlen(const unsigned char *p, size_t maxlen)
+{
+ size_t i;
+
+ for (i = 0; i <= maxlen; i++) {
+ if (p[i] == 0)
+ break;
+ }
+ if (i > maxlen)
+ return (-1);/* invalid */
+ return (i);
+}
+
+/* Read bytes as much as remaining. */
+static const void *
+cab_read_ahead_remaining(struct archive_read *a, size_t min, ssize_t *avail)
+{
+ const void *p;
+
+ while (min > 0) {
+ p = __archive_read_ahead(a, min, avail);
+ if (p != NULL)
+ return (p);
+ min--;
+ }
+ return (NULL);
+}
+
+/* Convert a path separator '\' -> '/' */
+static int
+cab_convert_path_separator_1(struct archive_string *fn, unsigned char attr)
+{
+ size_t i;
+ int mb;
+
+ /* Easy check if we have '\' in multi-byte string. */
+ mb = 0;
+ for (i = 0; i < archive_strlen(fn); i++) {
+ if (fn->s[i] == '\\') {
+ if (mb) {
+ /* This may be second byte of multi-byte
+ * character. */
+ break;
+ }
+ fn->s[i] = '/';
+ mb = 0;
+ } else if ((fn->s[i] & 0x80) && !(attr & ATTR_NAME_IS_UTF))
+ mb = 1;
+ else
+ mb = 0;
+ }
+ if (i == archive_strlen(fn))
+ return (0);
+ return (-1);
+}
+
+/*
+ * Replace a character '\' with '/' in wide character.
+ */
+static void
+cab_convert_path_separator_2(struct cab *cab, struct archive_entry *entry)
+{
+ const wchar_t *wp;
+ size_t i;
+
+ /* If a conversion to wide character failed, force the replacement. */
+ if ((wp = archive_entry_pathname_w(entry)) != NULL) {
+ archive_wstrcpy(&(cab->ws), wp);
+ for (i = 0; i < archive_strlen(&(cab->ws)); i++) {
+ if (cab->ws.s[i] == L'\\')
+ cab->ws.s[i] = L'/';
+ }
+ archive_entry_copy_pathname_w(entry, cab->ws.s);
+ }
+}
+
+/*
+ * Read CFHEADER, CFFOLDER and CFFILE.
+ */
+static int
+cab_read_header(struct archive_read *a)
+{
+ const unsigned char *p;
+ struct cab *cab;
+ struct cfheader *hd;
+ size_t bytes, used;
+ int64_t skip;
+ int err, i, len;
+ int cur_folder, prev_folder;
+ uint32_t offset32;
+
+ a->archive.archive_format = ARCHIVE_FORMAT_CAB;
+ if (a->archive.archive_format_name == NULL)
+ a->archive.archive_format_name = "CAB";
+
+ if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)
+ return (truncated_error(a));
+
+ cab = (struct cab *)(a->format->data);
+ if (cab->found_header == 0 &&
+ p[0] == 'M' && p[1] == 'Z') {
+ /* This is an executable? Must be self-extracting... */
+ err = cab_skip_sfx(a);
+ if (err < ARCHIVE_WARN)
+ return (err);
+
+ if ((p = __archive_read_ahead(a, sizeof(*p), NULL)) == NULL)
+ return (truncated_error(a));
+ }
+
+ cab->cab_offset = 0;
+ /*
+ * Read CFHEADER.
+ */
+ hd = &cab->cfheader;
+ if (p[CFHEADER_signature+0] != 'M' || p[CFHEADER_signature+1] != 'S' ||
+ p[CFHEADER_signature+2] != 'C' || p[CFHEADER_signature+3] != 'F') {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Couldn't find out CAB header");
+ return (ARCHIVE_FATAL);
+ }
+ hd->total_bytes = archive_le32dec(p + CFHEADER_cbCabinet);
+ hd->files_offset = archive_le32dec(p + CFHEADER_coffFiles);
+ hd->minor = p[CFHEADER_versionMinor];
+ hd->major = p[CFHEADER_versionMajor];
+ hd->folder_count = archive_le16dec(p + CFHEADER_cFolders);
+ if (hd->folder_count == 0)
+ goto invalid;
+ hd->file_count = archive_le16dec(p + CFHEADER_cFiles);
+ if (hd->file_count == 0)
+ goto invalid;
+ hd->flags = archive_le16dec(p + CFHEADER_flags);
+ hd->setid = archive_le16dec(p + CFHEADER_setID);
+ hd->cabinet = archive_le16dec(p + CFHEADER_iCabinet);
+ used = CFHEADER_iCabinet + 2;
+ if (hd->flags & RESERVE_PRESENT) {
+ uint16_t cfheader;
+ cfheader = archive_le16dec(p + CFHEADER_cbCFHeader);
+ if (cfheader > 60000U)
+ goto invalid;
+ hd->cffolder = p[CFHEADER_cbCFFolder];
+ hd->cfdata = p[CFHEADER_cbCFData];
+ used += 4;/* cbCFHeader, cbCFFolder and cbCFData */
+ used += cfheader;/* abReserve */
+ } else
+ hd->cffolder = 0;/* Avoid compiling warning. */
+ if (hd->flags & PREV_CABINET) {
+ /* How many bytes are used for szCabinetPrev. */
+ if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
+ return (truncated_error(a));
+ if ((len = cab_strnlen(p + used, 255)) <= 0)
+ goto invalid;
+ used += len + 1;
+ /* How many bytes are used for szDiskPrev. */
+ if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
+ return (truncated_error(a));
+ if ((len = cab_strnlen(p + used, 255)) <= 0)
+ goto invalid;
+ used += len + 1;
+ }
+ if (hd->flags & NEXT_CABINET) {
+ /* How many bytes are used for szCabinetNext. */
+ if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
+ return (truncated_error(a));
+ if ((len = cab_strnlen(p + used, 255)) <= 0)
+ goto invalid;
+ used += len + 1;
+ /* How many bytes are used for szDiskNext. */
+ if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
+ return (truncated_error(a));
+ if ((len = cab_strnlen(p + used, 255)) <= 0)
+ goto invalid;
+ used += len + 1;
+ }
+ __archive_read_consume(a, used);
+ cab->cab_offset += used;
+ used = 0;
+
+ /*
+ * Read CFFOLDER.
+ */
+ hd->folder_array = (struct cffolder *)calloc(
+ hd->folder_count, sizeof(struct cffolder));
+ if (hd->folder_array == NULL)
+ goto nomem;
+
+ bytes = 8;
+ if (hd->flags & RESERVE_PRESENT)
+ bytes += hd->cffolder;
+ bytes *= hd->folder_count;
+ if ((p = __archive_read_ahead(a, bytes, NULL)) == NULL)
+ return (truncated_error(a));
+ offset32 = 0;
+ for (i = 0; i < hd->folder_count; i++) {
+ struct cffolder *folder = &(hd->folder_array[i]);
+ folder->cfdata_offset_in_cab =
+ archive_le32dec(p + CFFOLDER_coffCabStart);
+ folder->cfdata_count = archive_le16dec(p+CFFOLDER_cCFData);
+ folder->comptype =
+ archive_le16dec(p+CFFOLDER_typeCompress) & 0x0F;
+ folder->compdata =
+ archive_le16dec(p+CFFOLDER_typeCompress) >> 8;
+ /* Get a compression name. */
+ if (folder->comptype <
+ sizeof(compression_name) / sizeof(compression_name[0]))
+ folder->compname = compression_name[folder->comptype];
+ else
+ folder->compname = "UNKNOWN";
+ p += 8;
+ used += 8;
+ if (hd->flags & RESERVE_PRESENT) {
+ p += hd->cffolder;/* abReserve */
+ used += hd->cffolder;
+ }
+ /*
+ * Sanity check if each data is acceptable.
+ */
+ if (offset32 >= folder->cfdata_offset_in_cab)
+ goto invalid;
+ offset32 = folder->cfdata_offset_in_cab;
+
+ /* Set a request to initialize zlib for the CFDATA of
+ * this folder. */
+ folder->decompress_init = 0;
+ }
+ __archive_read_consume(a, used);
+ cab->cab_offset += used;
+
+ /*
+ * Read CFFILE.
+ */
+ /* Seek read pointer to the offset of CFFILE if needed. */
+ skip = (int64_t)hd->files_offset - cab->cab_offset;
+ if (skip < 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Invalid offset of CFFILE %jd < %jd",
+ (intmax_t)hd->files_offset, (intmax_t)cab->cab_offset);
+ return (ARCHIVE_FATAL);
+ }
+ if (skip) {
+ __archive_read_consume(a, skip);
+ cab->cab_offset += skip;
+ }
+ /* Allocate memory for CFDATA */
+ hd->file_array = (struct cffile *)calloc(
+ hd->file_count, sizeof(struct cffile));
+ if (hd->file_array == NULL)
+ goto nomem;
+
+ prev_folder = -1;
+ for (i = 0; i < hd->file_count; i++) {
+ struct cffile *file = &(hd->file_array[i]);
+ ssize_t avail;
+
+ if ((p = __archive_read_ahead(a, 16, NULL)) == NULL)
+ return (truncated_error(a));
+ file->uncompressed_size = archive_le32dec(p + CFFILE_cbFile);
+ file->offset = archive_le32dec(p + CFFILE_uoffFolderStart);
+ file->folder = archive_le16dec(p + CFFILE_iFolder);
+ file->mtime = cab_dos_time(p + CFFILE_date_time);
+ file->attr = archive_le16dec(p + CFFILE_attribs);
+ __archive_read_consume(a, 16);
+
+ cab->cab_offset += 16;
+ if ((p = cab_read_ahead_remaining(a, 256, &avail)) == NULL)
+ return (truncated_error(a));
+ if ((len = cab_strnlen(p, avail-1)) <= 0)
+ goto invalid;
+
+ /* Copy a pathname. */
+ archive_string_init(&(file->pathname));
+ archive_strncpy(&(file->pathname), p, len);
+ __archive_read_consume(a, len + 1);
+ cab->cab_offset += len + 1;
+
+ /*
+ * Sanity check if each data is acceptable.
+ */
+ if (file->uncompressed_size > 0x7FFF8000)
+ goto invalid;/* Too large */
+ if ((int64_t)file->offset + (int64_t)file->uncompressed_size
+ > ARCHIVE_LITERAL_LL(0x7FFF8000))
+ goto invalid;/* Too large */
+ switch (file->folder) {
+ case iFoldCONTINUED_TO_NEXT:
+ /* This must be last file in a folder. */
+ if (i != hd->file_count -1)
+ goto invalid;
+ cur_folder = hd->folder_count -1;
+ break;
+ case iFoldCONTINUED_PREV_AND_NEXT:
+ /* This must be only one file in a folder. */
+ if (hd->file_count != 1)
+ goto invalid;
+ /* FALL THROUGH */
+ case iFoldCONTINUED_FROM_PREV:
+ /* This must be first file in a folder. */
+ if (i != 0)
+ goto invalid;
+ prev_folder = cur_folder = 0;
+ offset32 = file->offset;
+ break;
+ default:
+ if (file->folder >= hd->folder_count)
+ goto invalid;
+ cur_folder = file->folder;
+ break;
+ }
+ /* Dot not back track. */
+ if (cur_folder < prev_folder)
+ goto invalid;
+ if (cur_folder != prev_folder)
+ offset32 = 0;
+ prev_folder = cur_folder;
+
+ /* Make sure there are not any blanks from last file
+ * contents. */
+ if (offset32 != file->offset)
+ goto invalid;
+ offset32 += file->uncompressed_size;
+
+ /* CFDATA is available for file contents. */
+ if (file->uncompressed_size > 0 &&
+ hd->folder_array[cur_folder].cfdata_count == 0)
+ goto invalid;
+ }
+
+ if (hd->cabinet != 0 || hd->flags & (PREV_CABINET | NEXT_CABINET)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Multivolume cabinet file is unsupported");
+ return (ARCHIVE_WARN);
+ }
+ return (ARCHIVE_OK);
+invalid:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid CAB header");
+ return (ARCHIVE_FATAL);
+nomem:
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for CAB data");
+ return (ARCHIVE_FATAL);
+}
+
+static int
+archive_read_format_cab_read_header(struct archive_read *a,
+ struct archive_entry *entry)
+{
+ struct cab *cab;
+ struct cfheader *hd;
+ struct cffolder *prev_folder;
+ struct cffile *file;
+ struct archive_string_conv *sconv;
+ int err = ARCHIVE_OK, r;
+
+ cab = (struct cab *)(a->format->data);
+ if (cab->found_header == 0) {
+ err = cab_read_header(a);
+ if (err < ARCHIVE_WARN)
+ return (err);
+ /* We've found the header. */
+ cab->found_header = 1;
+ }
+ hd = &cab->cfheader;
+
+ if (hd->file_index >= hd->file_count) {
+ cab->end_of_archive = 1;
+ return (ARCHIVE_EOF);
+ }
+ file = &hd->file_array[hd->file_index++];
+
+ cab->end_of_entry = 0;
+ cab->end_of_entry_cleanup = 0;
+ cab->entry_compressed_bytes_read = 0;
+ cab->entry_uncompressed_bytes_read = 0;
+ cab->entry_unconsumed = 0;
+ cab->entry_cffile = file;
+
+ /*
+ * Choose a proper folder.
+ */
+ prev_folder = cab->entry_cffolder;
+ switch (file->folder) {
+ case iFoldCONTINUED_FROM_PREV:
+ case iFoldCONTINUED_PREV_AND_NEXT:
+ cab->entry_cffolder = &hd->folder_array[0];
+ break;
+ case iFoldCONTINUED_TO_NEXT:
+ cab->entry_cffolder = &hd->folder_array[hd->folder_count-1];
+ break;
+ default:
+ cab->entry_cffolder = &hd->folder_array[file->folder];
+ break;
+ }
+ /* If a cffolder of this file is changed, reset a cfdata to read
+ * file contents from next cfdata. */
+ if (prev_folder != cab->entry_cffolder)
+ cab->entry_cfdata = NULL;
+
+ /* If a pathname is UTF-8, prepare a string conversion object
+ * for UTF-8 and use it. */
+ if (file->attr & ATTR_NAME_IS_UTF) {
+ if (cab->sconv_utf8 == NULL) {
+ cab->sconv_utf8 =
+ archive_string_conversion_from_charset(
+ &(a->archive), "UTF-8", 1);
+ if (cab->sconv_utf8 == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ sconv = cab->sconv_utf8;
+ } else if (cab->sconv != NULL) {
+ /* Choose the conversion specified by the option. */
+ sconv = cab->sconv;
+ } else {
+ /* Choose the default conversion. */
+ if (!cab->init_default_conversion) {
+ cab->sconv_default =
+ archive_string_default_conversion_for_read(
+ &(a->archive));
+ cab->init_default_conversion = 1;
+ }
+ sconv = cab->sconv_default;
+ }
+
+ /*
+ * Set a default value and common data
+ */
+ r = cab_convert_path_separator_1(&(file->pathname), file->attr);
+ if (archive_entry_copy_pathname_l(entry, file->pathname.s,
+ archive_strlen(&(file->pathname)), sconv) != 0) {
+ if (errno == ENOMEM) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for Pathname");
+ return (ARCHIVE_FATAL);
+ }
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Pathname cannot be converted "
+ "from %s to current locale.",
+ archive_string_conversion_charset_name(sconv));
+ err = ARCHIVE_WARN;
+ }
+ if (r < 0) {
+ /* Convert a path separator '\' -> '/' */
+ cab_convert_path_separator_2(cab, entry);
+ }
+
+ archive_entry_set_size(entry, file->uncompressed_size);
+ if (file->attr & ATTR_RDONLY)
+ archive_entry_set_mode(entry, AE_IFREG | 0555);
+ else
+ archive_entry_set_mode(entry, AE_IFREG | 0777);
+ archive_entry_set_mtime(entry, file->mtime, 0);
+
+ cab->entry_bytes_remaining = file->uncompressed_size;
+ cab->entry_offset = 0;
+ /* We don't need compress data. */
+ if (file->uncompressed_size == 0)
+ cab->end_of_entry_cleanup = cab->end_of_entry = 1;
+
+ /* Set up a more descriptive format name. */
+ sprintf(cab->format_name, "CAB %d.%d (%s)",
+ hd->major, hd->minor, cab->entry_cffolder->compname);
+ a->archive.archive_format_name = cab->format_name;
+
+ return (err);
+}
+
+static int
+archive_read_format_cab_read_data(struct archive_read *a,
+ const void **buff, size_t *size, int64_t *offset)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ int r;
+
+ switch (cab->entry_cffile->folder) {
+ case iFoldCONTINUED_FROM_PREV:
+ case iFoldCONTINUED_TO_NEXT:
+ case iFoldCONTINUED_PREV_AND_NEXT:
+ *buff = NULL;
+ *size = 0;
+ *offset = 0;
+ archive_clear_error(&a->archive);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Cannot restore this file split in multivolume.");
+ return (ARCHIVE_FAILED);
+ default:
+ break;
+ }
+ if (cab->entry_unconsumed) {
+ /* Consume as much as the compressor actually used. */
+ r = cab_consume_cfdata(a, cab->entry_unconsumed);
+ cab->entry_unconsumed = 0;
+ if (r < 0)
+ return (r);
+ }
+ if (cab->end_of_archive || cab->end_of_entry) {
+ if (!cab->end_of_entry_cleanup) {
+ /* End-of-entry cleanup done. */
+ cab->end_of_entry_cleanup = 1;
+ }
+ *offset = cab->entry_offset;
+ *size = 0;
+ *buff = NULL;
+ return (ARCHIVE_EOF);
+ }
+
+ return (cab_read_data(a, buff, size, offset));
+}
+
+static uint32_t
+cab_checksum_cfdata_4(const void *p, size_t bytes, uint32_t seed)
+{
+ const unsigned char *b;
+ int u32num;
+ uint32_t sum;
+
+ u32num = bytes / 4;
+ sum = seed;
+ b = p;
+ while (--u32num >= 0) {
+ sum ^= archive_le32dec(b);
+ b += 4;
+ }
+ return (sum);
+}
+
+static uint32_t
+cab_checksum_cfdata(const void *p, size_t bytes, uint32_t seed)
+{
+ const unsigned char *b;
+ uint32_t sum;
+ uint32_t t;
+
+ sum = cab_checksum_cfdata_4(p, bytes, seed);
+ b = p;
+ b += bytes & ~3;
+ t = 0;
+ switch (bytes & 3) {
+ case 3:
+ t |= ((uint32_t)(*b++)) << 16;
+ /* FALL THROUGH */
+ case 2:
+ t |= ((uint32_t)(*b++)) << 8;
+ /* FALL THROUGH */
+ case 1:
+ t |= *b;
+ /* FALL THROUGH */
+ default:
+ break;
+ }
+ sum ^= t;
+
+ return (sum);
+}
+
+static void
+cab_checksum_update(struct archive_read *a, size_t bytes)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ struct cfdata *cfdata = cab->entry_cfdata;
+ const unsigned char *p;
+ size_t sumbytes;
+
+ if (cfdata->sum == 0 || cfdata->sum_ptr == NULL)
+ return;
+ /*
+ * Calculate the sum of this CFDATA.
+ * Make sure CFDATA must be calculated in four bytes.
+ */
+ p = cfdata->sum_ptr;
+ sumbytes = bytes;
+ if (cfdata->sum_extra_avail) {
+ while (cfdata->sum_extra_avail < 4 && sumbytes > 0) {
+ cfdata->sum_extra[
+ cfdata->sum_extra_avail++] = *p++;
+ sumbytes--;
+ }
+ if (cfdata->sum_extra_avail == 4) {
+ cfdata->sum_calculated = cab_checksum_cfdata_4(
+ cfdata->sum_extra, 4, cfdata->sum_calculated);
+ cfdata->sum_extra_avail = 0;
+ }
+ }
+ if (sumbytes) {
+ int odd = sumbytes & 3;
+ if (sumbytes - odd > 0)
+ cfdata->sum_calculated = cab_checksum_cfdata_4(
+ p, sumbytes - odd, cfdata->sum_calculated);
+ if (odd)
+ memcpy(cfdata->sum_extra, p + sumbytes - odd, odd);
+ cfdata->sum_extra_avail = odd;
+ }
+ cfdata->sum_ptr = NULL;
+}
+
+static int
+cab_checksum_finish(struct archive_read *a)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ struct cfdata *cfdata = cab->entry_cfdata;
+ int l;
+
+ /* Do not need to compute a sum. */
+ if (cfdata->sum == 0)
+ return (ARCHIVE_OK);
+
+ /*
+ * Calculate the sum of remaining CFDATA.
+ */
+ if (cfdata->sum_extra_avail) {
+ cfdata->sum_calculated =
+ cab_checksum_cfdata(cfdata->sum_extra,
+ cfdata->sum_extra_avail, cfdata->sum_calculated);
+ cfdata->sum_extra_avail = 0;
+ }
+
+ l = 4;
+ if (cab->cfheader.flags & RESERVE_PRESENT)
+ l += cab->cfheader.cfdata;
+ cfdata->sum_calculated = cab_checksum_cfdata(
+ cfdata->memimage + CFDATA_cbData, l, cfdata->sum_calculated);
+ if (cfdata->sum_calculated != cfdata->sum) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Checksum error CFDATA[%d] %x:%x in %d bytes",
+ cab->entry_cffolder->cfdata_index -1,
+ cfdata->sum, cfdata->sum_calculated,
+ cfdata->compressed_size);
+ return (ARCHIVE_FAILED);
+ }
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Read CFDATA if needed.
+ */
+static int
+cab_next_cfdata(struct archive_read *a)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ struct cfdata *cfdata = cab->entry_cfdata;
+
+ /* There are remaining bytes in current CFDATA, use it first. */
+ if (cfdata != NULL && cfdata->uncompressed_bytes_remaining > 0)
+ return (ARCHIVE_OK);
+
+ if (cfdata == NULL) {
+ int64_t skip;
+
+ cab->entry_cffolder->cfdata_index = 0;
+
+ /* Seek read pointer to the offset of CFDATA if needed. */
+ skip = cab->entry_cffolder->cfdata_offset_in_cab
+ - cab->cab_offset;
+ if (skip < 0) {
+ int folder_index;
+ switch (cab->entry_cffile->folder) {
+ case iFoldCONTINUED_FROM_PREV:
+ case iFoldCONTINUED_PREV_AND_NEXT:
+ folder_index = 0;
+ break;
+ case iFoldCONTINUED_TO_NEXT:
+ folder_index = cab->cfheader.folder_count-1;
+ break;
+ default:
+ folder_index = cab->entry_cffile->folder;
+ break;
+ }
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Invalid offset of CFDATA in folder(%d) %jd < %jd",
+ folder_index,
+ (intmax_t)cab->entry_cffolder->cfdata_offset_in_cab,
+ (intmax_t)cab->cab_offset);
+ return (ARCHIVE_FATAL);
+ }
+ if (skip > 0) {
+ if (__archive_read_consume(a, skip) < 0)
+ return (ARCHIVE_FATAL);
+ cab->cab_offset =
+ cab->entry_cffolder->cfdata_offset_in_cab;
+ }
+ }
+
+ /*
+ * Read a CFDATA.
+ */
+ if (cab->entry_cffolder->cfdata_index <
+ cab->entry_cffolder->cfdata_count) {
+ const unsigned char *p;
+ int l;
+
+ cfdata = &(cab->entry_cffolder->cfdata);
+ cab->entry_cffolder->cfdata_index++;
+ cab->entry_cfdata = cfdata;
+ cfdata->sum_calculated = 0;
+ cfdata->sum_extra_avail = 0;
+ cfdata->sum_ptr = NULL;
+ l = 8;
+ if (cab->cfheader.flags & RESERVE_PRESENT)
+ l += cab->cfheader.cfdata;
+ if ((p = __archive_read_ahead(a, l, NULL)) == NULL)
+ return (truncated_error(a));
+ cfdata->sum = archive_le32dec(p + CFDATA_csum);
+ cfdata->compressed_size = archive_le16dec(p + CFDATA_cbData);
+ cfdata->compressed_bytes_remaining = cfdata->compressed_size;
+ cfdata->uncompressed_size =
+ archive_le16dec(p + CFDATA_cbUncomp);
+ cfdata->uncompressed_bytes_remaining =
+ cfdata->uncompressed_size;
+ cfdata->uncompressed_avail = 0;
+ cfdata->read_offset = 0;
+ cfdata->unconsumed = 0;
+
+ /*
+ * Sanity check if data size is acceptable.
+ */
+ if (cfdata->compressed_size == 0 ||
+ cfdata->compressed_size > (0x8000+6144))
+ goto invalid;
+ if (cfdata->uncompressed_size > 0x8000)
+ goto invalid;
+ if (cfdata->uncompressed_size == 0) {
+ switch (cab->entry_cffile->folder) {
+ case iFoldCONTINUED_PREV_AND_NEXT:
+ case iFoldCONTINUED_TO_NEXT:
+ break;
+ case iFoldCONTINUED_FROM_PREV:
+ default:
+ goto invalid;
+ }
+ }
+ /* If CFDATA is not last in a folder, an uncompressed
+ * size must be 0x8000(32KBi) */
+ if ((cab->entry_cffolder->cfdata_index <
+ cab->entry_cffolder->cfdata_count) &&
+ cfdata->uncompressed_size != 0x8000)
+ goto invalid;
+
+ /* A compressed data size and an uncompressed data size must
+ * be the same in no compression mode. */
+ if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&
+ cfdata->compressed_size != cfdata->uncompressed_size)
+ goto invalid;
+
+ /*
+ * Save CFDATA image for sum check.
+ */
+ if (cfdata->memimage_size < (size_t)l) {
+ free(cfdata->memimage);
+ cfdata->memimage = malloc(l);
+ if (cfdata->memimage == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for CAB data");
+ return (ARCHIVE_FATAL);
+ }
+ cfdata->memimage_size = l;
+ }
+ memcpy(cfdata->memimage, p, l);
+
+ /* Consume bytes as much as we used. */
+ __archive_read_consume(a, l);
+ cab->cab_offset += l;
+ } else if (cab->entry_cffolder->cfdata_count > 0) {
+ /* Run out of all CFDATA in a folder. */
+ cfdata->compressed_size = 0;
+ cfdata->uncompressed_size = 0;
+ cfdata->compressed_bytes_remaining = 0;
+ cfdata->uncompressed_bytes_remaining = 0;
+ } else {
+ /* Current folder does not have any CFDATA. */
+ cfdata = &(cab->entry_cffolder->cfdata);
+ cab->entry_cfdata = cfdata;
+ memset(cfdata, 0, sizeof(*cfdata));
+ }
+ return (ARCHIVE_OK);
+invalid:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid CFDATA");
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Read ahead CFDATA.
+ */
+static const void *
+cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ int err;
+
+ err = cab_next_cfdata(a);
+ if (err < ARCHIVE_OK) {
+ *avail = err;
+ return (NULL);
+ }
+
+ switch (cab->entry_cffolder->comptype) {
+ case COMPTYPE_NONE:
+ return (cab_read_ahead_cfdata_none(a, avail));
+ case COMPTYPE_MSZIP:
+ return (cab_read_ahead_cfdata_deflate(a, avail));
+ case COMPTYPE_LZX:
+ return (cab_read_ahead_cfdata_lzx(a, avail));
+ default: /* Unsupported compression. */
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unsupported CAB compression : %s",
+ cab->entry_cffolder->compname);
+ *avail = ARCHIVE_FAILED;
+ return (NULL);
+ }
+}
+
+/*
+ * Read ahead CFDATA as uncompressed data.
+ */
+static const void *
+cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ struct cfdata *cfdata;
+ const void *d;
+ int64_t skipped_bytes;
+
+ cfdata = cab->entry_cfdata;
+
+ if (cfdata->uncompressed_avail == 0 &&
+ cfdata->read_offset > 0) {
+ /* we've already skipped some bytes before really read. */
+ skipped_bytes = cfdata->read_offset;
+ cfdata->read_offset = 0;
+ cfdata->uncompressed_bytes_remaining += skipped_bytes;
+ } else
+ skipped_bytes = 0;
+ do {
+ /*
+ * Note: '1' here is a performance optimization.
+ * Recall that the decompression layer returns a count of
+ * available bytes; asking for more than that forces the
+ * decompressor to combine reads by copying data.
+ */
+ d = __archive_read_ahead(a, 1, avail);
+ if (*avail <= 0) {
+ *avail = truncated_error(a);
+ return (NULL);
+ }
+ if (*avail > cfdata->uncompressed_bytes_remaining)
+ *avail = cfdata->uncompressed_bytes_remaining;
+ cfdata->uncompressed_avail = cfdata->uncompressed_size;
+ cfdata->unconsumed = *avail;
+ cfdata->sum_ptr = d;
+ if (skipped_bytes > 0) {
+ skipped_bytes =
+ cab_minimum_consume_cfdata(a, skipped_bytes);
+ if (skipped_bytes < 0) {
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ continue;
+ }
+ } while (0);
+
+ return (d);
+}
+
+/*
+ * Read ahead CFDATA as deflate data.
+ */
+#ifdef HAVE_ZLIB_H
+static const void *
+cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ struct cfdata *cfdata;
+ const void *d;
+ int r, mszip;
+ uint16_t uavail;
+ char eod = 0;
+
+ cfdata = cab->entry_cfdata;
+ /* If the buffer hasn't been allocated, allocate it now. */
+ if (cab->uncompressed_buffer == NULL) {
+ cab->uncompressed_buffer_size = 0x8000;
+ cab->uncompressed_buffer
+ = (unsigned char *)malloc(cab->uncompressed_buffer_size);
+ if (cab->uncompressed_buffer == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory for CAB reader");
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ }
+
+ uavail = cfdata->uncompressed_avail;
+ if (uavail == cfdata->uncompressed_size) {
+ d = cab->uncompressed_buffer + cfdata->read_offset;
+ *avail = uavail - cfdata->read_offset;
+ return (d);
+ }
+
+ if (!cab->entry_cffolder->decompress_init) {
+ cab->stream.next_in = NULL;
+ cab->stream.avail_in = 0;
+ cab->stream.total_in = 0;
+ cab->stream.next_out = NULL;
+ cab->stream.avail_out = 0;
+ cab->stream.total_out = 0;
+ if (cab->stream_valid)
+ r = inflateReset(&cab->stream);
+ else
+ r = inflateInit2(&cab->stream,
+ -15 /* Don't check for zlib header */);
+ if (r != Z_OK) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Can't initialize deflate decompression.");
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ /* Stream structure has been set up. */
+ cab->stream_valid = 1;
+ /* We've initialized decompression for this stream. */
+ cab->entry_cffolder->decompress_init = 1;
+ }
+
+ if (cfdata->compressed_bytes_remaining == cfdata->compressed_size)
+ mszip = 2;
+ else
+ mszip = 0;
+ eod = 0;
+ cab->stream.total_out = uavail;
+ /*
+ * We always uncompress all data in current CFDATA.
+ */
+ while (!eod && cab->stream.total_out < cfdata->uncompressed_size) {
+ ssize_t bytes_avail;
+
+ cab->stream.next_out =
+ cab->uncompressed_buffer + cab->stream.total_out;
+ cab->stream.avail_out =
+ cfdata->uncompressed_size - cab->stream.total_out;
+
+ d = __archive_read_ahead(a, 1, &bytes_avail);
+ if (bytes_avail <= 0) {
+ *avail = truncated_error(a);
+ return (NULL);
+ }
+ if (bytes_avail > cfdata->compressed_bytes_remaining)
+ bytes_avail = cfdata->compressed_bytes_remaining;
+ /*
+ * A bug in zlib.h: stream.next_in should be marked 'const'
+ * but isn't (the library never alters data through the
+ * next_in pointer, only reads it). The result: this ugly
+ * cast to remove 'const'.
+ */
+ cab->stream.next_in = (Bytef *)(uintptr_t)d;
+ cab->stream.avail_in = bytes_avail;
+ cab->stream.total_in = 0;
+
+ /* Cut out a tow-byte MSZIP signature(0x43, 0x4b). */
+ if (mszip > 0) {
+ if (bytes_avail <= mszip) {
+ if (mszip == 2) {
+ if (cab->stream.next_in[0] != 0x43)
+ goto nomszip;
+ if (bytes_avail > 1 &&
+ cab->stream.next_in[1] != 0x4b)
+ goto nomszip;
+ } else if (cab->stream.next_in[0] != 0x4b)
+ goto nomszip;
+ cfdata->unconsumed = bytes_avail;
+ cfdata->sum_ptr = d;
+ if (cab_minimum_consume_cfdata(
+ a, cfdata->unconsumed) < 0) {
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ mszip -= bytes_avail;
+ continue;
+ }
+ if (mszip == 1 && cab->stream.next_in[0] != 0x4b)
+ goto nomszip;
+ else if (cab->stream.next_in[0] != 0x43 ||
+ cab->stream.next_in[1] != 0x4b)
+ goto nomszip;
+ cab->stream.next_in += mszip;
+ cab->stream.avail_in -= mszip;
+ cab->stream.total_in += mszip;
+ mszip = 0;
+ }
+
+ r = inflate(&cab->stream, 0);
+ switch (r) {
+ case Z_OK:
+ break;
+ case Z_STREAM_END:
+ eod = 1;
+ break;
+ default:
+ goto zlibfailed;
+ }
+ cfdata->unconsumed = cab->stream.total_in;
+ cfdata->sum_ptr = d;
+ if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ }
+ uavail = cab->stream.total_out;
+
+ if (uavail < cfdata->uncompressed_size) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Invalid uncompressed size (%d < %d)",
+ uavail, cfdata->uncompressed_size);
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+
+ /*
+ * Note: I suspect there is a bug in makecab.exe because, in rare
+ * case, compressed bytes are still remaining regardless we have
+ * gotten all uncompressed bytes, which size is recoded in CFDATA,
+ * as much as we need, and we have to use the garbage so as to
+ * correctly compute the sum of CFDATA accordingly.
+ */
+ if (cfdata->compressed_bytes_remaining > 0) {
+ ssize_t bytes_avail;
+
+ d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
+ &bytes_avail);
+ if (bytes_avail <= 0) {
+ *avail = truncated_error(a);
+ return (NULL);
+ }
+ cfdata->unconsumed = cfdata->compressed_bytes_remaining;
+ cfdata->sum_ptr = d;
+ if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ }
+
+ /*
+ * Set dictionary data for decompressing of next CFDATA, which
+ * in the same folder. This is why we always do decompress CFDATA
+ * even if beginning CFDATA or some of CFDATA are not used in
+ * skipping file data.
+ */
+ if (cab->entry_cffolder->cfdata_index <
+ cab->entry_cffolder->cfdata_count) {
+ r = inflateReset(&cab->stream);
+ if (r != Z_OK)
+ goto zlibfailed;
+ r = inflateSetDictionary(&cab->stream,
+ cab->uncompressed_buffer, cfdata->uncompressed_size);
+ if (r != Z_OK)
+ goto zlibfailed;
+ }
+
+ d = cab->uncompressed_buffer + cfdata->read_offset;
+ *avail = uavail - cfdata->read_offset;
+ cfdata->uncompressed_avail = uavail;
+
+ return (d);
+
+zlibfailed:
+ switch (r) {
+ case Z_MEM_ERROR:
+ archive_set_error(&a->archive, ENOMEM,
+ "Out of memory for deflate decompression");
+ break;
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Deflate decompression failed (%d)", r);
+ break;
+ }
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+nomszip:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "CFDATA incorrect(no MSZIP signature)");
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+}
+
+#else /* HAVE_ZLIB_H */
+
+static const void *
+cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
+{
+ *avail = ARCHIVE_FATAL;
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "libarchive compiled without deflate support (no libz)");
+ return (NULL);
+}
+
+#endif /* HAVE_ZLIB_H */
+
+static const void *
+cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ struct cfdata *cfdata;
+ const void *d;
+ int r;
+ uint16_t uavail;
+
+ cfdata = cab->entry_cfdata;
+ /* If the buffer hasn't been allocated, allocate it now. */
+ if (cab->uncompressed_buffer == NULL) {
+ cab->uncompressed_buffer_size = 0x8000;
+ cab->uncompressed_buffer
+ = (unsigned char *)malloc(cab->uncompressed_buffer_size);
+ if (cab->uncompressed_buffer == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory for CAB reader");
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ }
+
+ uavail = cfdata->uncompressed_avail;
+ if (uavail == cfdata->uncompressed_size) {
+ d = cab->uncompressed_buffer + cfdata->read_offset;
+ *avail = uavail - cfdata->read_offset;
+ return (d);
+ }
+
+ if (!cab->entry_cffolder->decompress_init) {
+ r = lzx_decode_init(&cab->xstrm,
+ cab->entry_cffolder->compdata);
+ if (r != ARCHIVE_OK) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Can't initialize LZX decompression.");
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ /* We've initialized decompression for this stream. */
+ cab->entry_cffolder->decompress_init = 1;
+ }
+
+ /* Clean up remaining bits of previous CFDATA. */
+ lzx_cleanup_bitstream(&cab->xstrm);
+ cab->xstrm.total_out = uavail;
+ while (cab->xstrm.total_out < cfdata->uncompressed_size) {
+ ssize_t bytes_avail;
+
+ cab->xstrm.next_out =
+ cab->uncompressed_buffer + cab->xstrm.total_out;
+ cab->xstrm.avail_out =
+ cfdata->uncompressed_size - cab->xstrm.total_out;
+
+ d = __archive_read_ahead(a, 1, &bytes_avail);
+ if (bytes_avail <= 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated CAB file data");
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ if (bytes_avail > cfdata->compressed_bytes_remaining)
+ bytes_avail = cfdata->compressed_bytes_remaining;
+
+ cab->xstrm.next_in = d;
+ cab->xstrm.avail_in = bytes_avail;
+ cab->xstrm.total_in = 0;
+ r = lzx_decode(&cab->xstrm,
+ cfdata->compressed_bytes_remaining == bytes_avail);
+ switch (r) {
+ case ARCHIVE_OK:
+ case ARCHIVE_EOF:
+ break;
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "LZX decompression failed (%d)", r);
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ cfdata->unconsumed = cab->xstrm.total_in;
+ cfdata->sum_ptr = d;
+ if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ }
+
+ uavail = cab->xstrm.total_out;
+ /*
+ * Make sure a read pointer advances to next CFDATA.
+ */
+ if (cfdata->compressed_bytes_remaining > 0) {
+ ssize_t bytes_avail;
+
+ d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
+ &bytes_avail);
+ if (bytes_avail <= 0) {
+ *avail = truncated_error(a);
+ return (NULL);
+ }
+ cfdata->unconsumed = cfdata->compressed_bytes_remaining;
+ cfdata->sum_ptr = d;
+ if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ }
+
+ /*
+ * Translation reversal of x86 proccessor CALL byte sequence(E8).
+ */
+ lzx_translation(&cab->xstrm, cab->uncompressed_buffer,
+ cfdata->uncompressed_size,
+ (cab->entry_cffolder->cfdata_index-1) * 0x8000);
+
+ d = cab->uncompressed_buffer + cfdata->read_offset;
+ *avail = uavail - cfdata->read_offset;
+ cfdata->uncompressed_avail = uavail;
+
+ return (d);
+}
+
+/*
+ * Consume CFDATA.
+ * We always decompress CFDATA to consume CFDATA as much as we need
+ * in uncompressed bytes because all CFDATA in a folder are related
+ * so we do not skip any CFDATA without decompressing.
+ * Note: If the folder of a CFFILE is iFoldCONTINUED_PREV_AND_NEXT or
+ * iFoldCONTINUED_FROM_PREV, we won't decompress because a CFDATA for
+ * the CFFILE is remaining bytes of previous Multivolume CAB file.
+ */
+static int64_t
+cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ struct cfdata *cfdata;
+ int64_t cbytes, rbytes;
+ int err;
+
+ rbytes = cab_minimum_consume_cfdata(a, consumed_bytes);
+ if (rbytes < 0)
+ return (ARCHIVE_FATAL);
+
+ cfdata = cab->entry_cfdata;
+ while (rbytes > 0) {
+ ssize_t avail;
+
+ if (cfdata->compressed_size == 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid CFDATA");
+ return (ARCHIVE_FATAL);
+ }
+ cbytes = cfdata->uncompressed_bytes_remaining;
+ if (cbytes > rbytes)
+ cbytes = rbytes;
+ rbytes -= cbytes;
+
+ if (cfdata->uncompressed_avail == 0 &&
+ (cab->entry_cffolder->comptype == COMPTYPE_NONE ||
+ cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT ||
+ cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) {
+ /* We have not read any data yet. */
+ if (cbytes == cfdata->uncompressed_bytes_remaining) {
+ /* Skip whole current CFDATA. */
+ __archive_read_consume(a,
+ cfdata->compressed_size);
+ cab->cab_offset += cfdata->compressed_size;
+ cfdata->compressed_bytes_remaining = 0;
+ cfdata->uncompressed_bytes_remaining = 0;
+ err = cab_next_cfdata(a);
+ if (err < 0)
+ return (err);
+ cfdata = cab->entry_cfdata;
+ if (cfdata->uncompressed_size == 0) {
+ switch (cab->entry_cffile->folder) {
+ case iFoldCONTINUED_PREV_AND_NEXT:
+ case iFoldCONTINUED_TO_NEXT:
+ case iFoldCONTINUED_FROM_PREV:
+ rbytes = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ continue;
+ }
+ cfdata->read_offset += cbytes;
+ cfdata->uncompressed_bytes_remaining -= cbytes;
+ break;
+ } else if (cbytes == 0) {
+ err = cab_next_cfdata(a);
+ if (err < 0)
+ return (err);
+ cfdata = cab->entry_cfdata;
+ if (cfdata->uncompressed_size == 0) {
+ switch (cab->entry_cffile->folder) {
+ case iFoldCONTINUED_PREV_AND_NEXT:
+ case iFoldCONTINUED_TO_NEXT:
+ case iFoldCONTINUED_FROM_PREV:
+ return (ARCHIVE_FATAL);
+ default:
+ break;
+ }
+ }
+ continue;
+ }
+ while (cbytes > 0) {
+ (void)cab_read_ahead_cfdata(a, &avail);
+ if (avail <= 0)
+ return (ARCHIVE_FATAL);
+ if (avail > cbytes)
+ avail = cbytes;
+ if (cab_minimum_consume_cfdata(a, avail) < 0)
+ return (ARCHIVE_FATAL);
+ cbytes -= avail;
+ }
+ }
+ return (consumed_bytes);
+}
+
+/*
+ * Consume CFDATA as much as we have already gotten and
+ * compute the sum of CFDATA.
+ */
+static int64_t
+cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ struct cfdata *cfdata;
+ int64_t cbytes, rbytes;
+ int err;
+
+ cfdata = cab->entry_cfdata;
+ rbytes = consumed_bytes;
+ if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {
+ if (consumed_bytes < cfdata->unconsumed)
+ cbytes = consumed_bytes;
+ else
+ cbytes = cfdata->unconsumed;
+ rbytes -= cbytes;
+ cfdata->read_offset += cbytes;
+ cfdata->uncompressed_bytes_remaining -= cbytes;
+ cfdata->unconsumed -= cbytes;
+ } else {
+ cbytes = cfdata->uncompressed_avail - cfdata->read_offset;
+ if (cbytes > 0) {
+ if (consumed_bytes < cbytes)
+ cbytes = consumed_bytes;
+ rbytes -= cbytes;
+ cfdata->read_offset += cbytes;
+ cfdata->uncompressed_bytes_remaining -= cbytes;
+ }
+
+ if (cfdata->unconsumed) {
+ cbytes = cfdata->unconsumed;
+ cfdata->unconsumed = 0;
+ } else
+ cbytes = 0;
+ }
+ if (cbytes) {
+ /* Compute the sum. */
+ cab_checksum_update(a, cbytes);
+
+ /* Consume as much as the compressor actually used. */
+ __archive_read_consume(a, cbytes);
+ cab->cab_offset += cbytes;
+ cfdata->compressed_bytes_remaining -= cbytes;
+ if (cfdata->compressed_bytes_remaining == 0) {
+ err = cab_checksum_finish(a);
+ if (err < 0)
+ return (err);
+ }
+ }
+ return (rbytes);
+}
+
+/*
+ * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
+ * cab->end_of_entry if it consumes all of the data.
+ */
+static int
+cab_read_data(struct archive_read *a, const void **buff,
+ size_t *size, int64_t *offset)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ ssize_t bytes_avail;
+
+ if (cab->entry_bytes_remaining == 0) {
+ *buff = NULL;
+ *size = 0;
+ *offset = cab->entry_offset;
+ cab->end_of_entry = 1;
+ return (ARCHIVE_OK);
+ }
+
+ *buff = cab_read_ahead_cfdata(a, &bytes_avail);
+ if (bytes_avail <= 0) {
+ *buff = NULL;
+ *size = 0;
+ *offset = 0;
+ if (bytes_avail == 0 &&
+ cab->entry_cfdata->uncompressed_size == 0) {
+ /* All of CFDATA in a folder has been handled. */
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT, "Invalid CFDATA");
+ return (ARCHIVE_FATAL);
+ } else
+ return (bytes_avail);
+ }
+ if (bytes_avail > cab->entry_bytes_remaining)
+ bytes_avail = cab->entry_bytes_remaining;
+
+ *size = bytes_avail;
+ *offset = cab->entry_offset;
+ cab->entry_offset += bytes_avail;
+ cab->entry_bytes_remaining -= bytes_avail;
+ if (cab->entry_bytes_remaining == 0)
+ cab->end_of_entry = 1;
+ cab->entry_unconsumed = bytes_avail;
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_cab_read_data_skip(struct archive_read *a)
+{
+ struct cab *cab;
+ int64_t bytes_skipped;
+ int r;
+
+ cab = (struct cab *)(a->format->data);
+
+ if (cab->end_of_archive)
+ return (ARCHIVE_EOF);
+
+ if (cab->entry_unconsumed) {
+ /* Consume as much as the compressor actually used. */
+ r = cab_consume_cfdata(a, cab->entry_unconsumed);
+ cab->entry_unconsumed = 0;
+ if (r < 0)
+ return (r);
+ } else if (cab->entry_cfdata == NULL) {
+ r = cab_next_cfdata(a);
+ if (r < 0)
+ return (r);
+ }
+
+ /* if we've already read to end of data, we're done. */
+ if (cab->end_of_entry_cleanup)
+ return (ARCHIVE_OK);
+
+ /*
+ * If the length is at the beginning, we can skip the
+ * compressed data much more quickly.
+ */
+ bytes_skipped = cab_consume_cfdata(a, cab->entry_bytes_remaining);
+ if (bytes_skipped < 0)
+ return (ARCHIVE_FATAL);
+
+ /* This entry is finished and done. */
+ cab->end_of_entry_cleanup = cab->end_of_entry = 1;
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_cab_cleanup(struct archive_read *a)
+{
+ struct cab *cab = (struct cab *)(a->format->data);
+ struct cfheader *hd = &cab->cfheader;
+ int i;
+
+ if (hd->folder_array != NULL) {
+ for (i = 0; i < hd->folder_count; i++)
+ free(hd->folder_array[i].cfdata.memimage);
+ free(hd->folder_array);
+ }
+ if (hd->file_array != NULL) {
+ for (i = 0; i < cab->cfheader.file_count; i++)
+ archive_string_free(&(hd->file_array[i].pathname));
+ free(hd->file_array);
+ }
+#ifdef HAVE_ZLIB_H
+ if (cab->stream_valid)
+ inflateEnd(&cab->stream);
+#endif
+ lzx_decode_free(&cab->xstrm);
+ archive_wstring_free(&cab->ws);
+ free(cab->uncompressed_buffer);
+ free(cab);
+ (a->format->data) = NULL;
+ return (ARCHIVE_OK);
+}
+
+/* Convert an MSDOS-style date/time into Unix-style time. */
+static time_t
+cab_dos_time(const unsigned char *p)
+{
+ int msTime, msDate;
+ struct tm ts;
+
+ msDate = archive_le16dec(p);
+ msTime = archive_le16dec(p+2);
+
+ memset(&ts, 0, sizeof(ts));
+ ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
+ ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
+ ts.tm_mday = msDate & 0x1f; /* Day of month. */
+ ts.tm_hour = (msTime >> 11) & 0x1f;
+ ts.tm_min = (msTime >> 5) & 0x3f;
+ ts.tm_sec = (msTime << 1) & 0x3e;
+ ts.tm_isdst = -1;
+ return (mktime(&ts));
+}
+
+/*****************************************************************
+ *
+ * LZX decompression code.
+ *
+ *****************************************************************/
+
+/*
+ * Initialize LZX decoder.
+ *
+ * Returns ARCHIVE_OK if initialization was successful.
+ * Returns ARCHIVE_FAILED if w_bits has unsupported value.
+ * Returns ARCHIVE_FATAL if initialization failed; memory allocation
+ * error occurred.
+ */
+static int
+lzx_decode_init(struct lzx_stream *strm, int w_bits)
+{
+ struct lzx_dec *ds;
+ int slot, w_size, w_slot;
+ int base, footer;
+ int base_inc[18];
+
+ if (strm->ds == NULL) {
+ strm->ds = calloc(1, sizeof(*strm->ds));
+ if (strm->ds == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ ds = strm->ds;
+ ds->error = ARCHIVE_FAILED;
+
+ /* Allow bits from 15(32KBi) up to 21(2MBi) */
+ if (w_bits < SLOT_BASE || w_bits > SLOT_MAX)
+ return (ARCHIVE_FAILED);
+
+ ds->error = ARCHIVE_FATAL;
+
+ /*
+ * Alloc window
+ */
+ w_size = ds->w_size;
+ w_slot = slots[w_bits - SLOT_BASE];
+ ds->w_size = 1U << w_bits;
+ ds->w_mask = ds->w_size -1;
+ if (ds->w_buff == NULL || w_size != ds->w_size) {
+ free(ds->w_buff);
+ ds->w_buff = malloc(ds->w_size);
+ if (ds->w_buff == NULL)
+ return (ARCHIVE_FATAL);
+ free(ds->pos_tbl);
+ ds->pos_tbl = malloc(sizeof(ds->pos_tbl[0]) * w_slot);
+ if (ds->pos_tbl == NULL)
+ return (ARCHIVE_FATAL);
+ lzx_huffman_free(&(ds->mt));
+ }
+
+ for (footer = 0; footer < 18; footer++)
+ base_inc[footer] = 1 << footer;
+ base = footer = 0;
+ for (slot = 0; slot < w_slot; slot++) {
+ int n;
+ if (footer == 0)
+ base = slot;
+ else
+ base += base_inc[footer];
+ if (footer < 17) {
+ footer = -2;
+ for (n = base; n; n >>= 1)
+ footer++;
+ if (footer <= 0)
+ footer = 0;
+ }
+ ds->pos_tbl[slot].base = base;
+ ds->pos_tbl[slot].footer_bits = footer;
+ }
+
+ ds->w_pos = 0;
+ ds->state = 0;
+ ds->br.cache_buffer = 0;
+ ds->br.cache_avail = 0;
+ ds->r0 = ds->r1 = ds->r2 = 1;
+
+ /* Initialize aligned offset tree. */
+ if (lzx_huffman_init(&(ds->at), 8, 8) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ /* Initialize pre-tree. */
+ if (lzx_huffman_init(&(ds->pt), 20, 10) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ /* Initialize Main tree. */
+ if (lzx_huffman_init(&(ds->mt), 256+(w_slot<<3), 16)
+ != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ /* Initialize Length tree. */
+ if (lzx_huffman_init(&(ds->lt), 249, 16) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ ds->error = 0;
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Release LZX decoder.
+ */
+static void
+lzx_decode_free(struct lzx_stream *strm)
+{
+
+ if (strm->ds == NULL)
+ return;
+ free(strm->ds->w_buff);
+ free(strm->ds->pos_tbl);
+ lzx_huffman_free(&(strm->ds->at));
+ lzx_huffman_free(&(strm->ds->pt));
+ lzx_huffman_free(&(strm->ds->mt));
+ lzx_huffman_free(&(strm->ds->lt));
+ free(strm->ds);
+ strm->ds = NULL;
+}
+
+/*
+ * E8 Call Translation reversal.
+ */
+static void
+lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
+{
+ struct lzx_dec *ds = strm->ds;
+ unsigned char *b, *end;
+
+ if (!ds->translation || size <= 10)
+ return;
+ b = p;
+ end = b + size - 10;
+ while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {
+ size_t i = b - (unsigned char *)p;
+ int32_t cp, displacement, value;
+
+ cp = offset + i;
+ value = archive_le32dec(&b[1]);
+ if (value >= -cp && value < (int32_t)ds->translation_size) {
+ if (value >= 0)
+ displacement = value - cp;
+ else
+ displacement = value + ds->translation_size;
+ archive_le32enc(&b[1], (uint32_t)displacement);
+ }
+ b += 5;
+ }
+}
+
+/*
+ * Bit stream reader.
+ */
+/* Check that the cache buffer has enough bits. */
+#define lzx_br_has(br, n) ((br)->cache_avail >= n)
+/* Get compressed data by bit. */
+#define lzx_br_bits(br, n) \
+ (((uint32_t)((br)->cache_buffer >> \
+ ((br)->cache_avail - (n)))) & cache_masks[n])
+#define lzx_br_bits_forced(br, n) \
+ (((uint32_t)((br)->cache_buffer << \
+ ((n) - (br)->cache_avail))) & cache_masks[n])
+/* Read ahead to make sure the cache buffer has enough compressed data we
+ * will use.
+ * True : completed, there is enough data in the cache buffer.
+ * False : we met that strm->next_in is empty, we have to get following
+ * bytes. */
+#define lzx_br_read_ahead_0(strm, br, n) \
+ (lzx_br_has((br), (n)) || lzx_br_fillup(strm, br))
+/* True : the cache buffer has some bits as much as we need.
+ * False : there are no enough bits in the cache buffer to be used,
+ * we have to get following bytes if we could. */
+#define lzx_br_read_ahead(strm, br, n) \
+ (lzx_br_read_ahead_0((strm), (br), (n)) || lzx_br_has((br), (n)))
+
+/* Notify how many bits we consumed. */
+#define lzx_br_consume(br, n) ((br)->cache_avail -= (n))
+#define lzx_br_consume_unalined_bits(br) ((br)->cache_avail &= ~0x0f)
+
+static const uint32_t cache_masks[] = {
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007,
+ 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
+ 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
+ 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
+ 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
+ 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
+ 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
+ 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+/*
+ * Shift away used bits in the cache data and fill it up with following bits.
+ * Call this when cache buffer does not have enough bits you need.
+ *
+ * Returns 1 if the cache buffer is full.
+ * Returns 0 if the cache buffer is not full; input buffer is empty.
+ */
+static int
+lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
+{
+/*
+ * x86 proccessor family can read misaligned data without an access error.
+ */
+ int n = CACHE_BITS - br->cache_avail;
+
+ for (;;) {
+ switch (n >> 4) {
+ case 4:
+ if (strm->avail_in >= 8) {
+ br->cache_buffer =
+ ((uint64_t)strm->next_in[1]) << 56 |
+ ((uint64_t)strm->next_in[0]) << 48 |
+ ((uint64_t)strm->next_in[3]) << 40 |
+ ((uint64_t)strm->next_in[2]) << 32 |
+ ((uint32_t)strm->next_in[5]) << 24 |
+ ((uint32_t)strm->next_in[4]) << 16 |
+ ((uint32_t)strm->next_in[7]) << 8 |
+ (uint32_t)strm->next_in[6];
+ strm->next_in += 8;
+ strm->avail_in -= 8;
+ br->cache_avail += 8 * 8;
+ return (1);
+ }
+ break;
+ case 3:
+ if (strm->avail_in >= 6) {
+ br->cache_buffer =
+ (br->cache_buffer << 48) |
+ ((uint64_t)strm->next_in[1]) << 40 |
+ ((uint64_t)strm->next_in[0]) << 32 |
+ ((uint32_t)strm->next_in[3]) << 24 |
+ ((uint32_t)strm->next_in[2]) << 16 |
+ ((uint32_t)strm->next_in[5]) << 8 |
+ (uint32_t)strm->next_in[4];
+ strm->next_in += 6;
+ strm->avail_in -= 6;
+ br->cache_avail += 6 * 8;
+ return (1);
+ }
+ break;
+ case 0:
+ /* We have enough compressed data in
+ * the cache buffer.*/
+ return (1);
+ default:
+ break;
+ }
+ if (strm->avail_in < 2) {
+ /* There is not enough compressed data to
+ * fill up the cache buffer. */
+ if (strm->avail_in == 1) {
+ br->odd = *strm->next_in++;
+ strm->avail_in--;
+ br->have_odd = 1;
+ }
+ return (0);
+ }
+ br->cache_buffer =
+ (br->cache_buffer << 16) |
+ archive_le16dec(strm->next_in);
+ strm->next_in += 2;
+ strm->avail_in -= 2;
+ br->cache_avail += 16;
+ n -= 16;
+ }
+}
+
+static void
+lzx_br_fixup(struct lzx_stream *strm, struct lzx_br *br)
+{
+ int n = CACHE_BITS - br->cache_avail;
+
+ if (br->have_odd && n >= 16 && strm->avail_in > 0) {
+ br->cache_buffer =
+ (br->cache_buffer << 16) |
+ ((uint16_t)(*strm->next_in)) << 8 | br->odd;
+ strm->next_in++;
+ strm->avail_in--;
+ br->cache_avail += 16;
+ br->have_odd = 0;
+ }
+}
+
+static void
+lzx_cleanup_bitstream(struct lzx_stream *strm)
+{
+ strm->ds->br.cache_avail = 0;
+ strm->ds->br.have_odd = 0;
+}
+
+/*
+ * Decode LZX.
+ *
+ * 1. Returns ARCHIVE_OK if output buffer or input buffer are empty.
+ * Please set available buffer and call this function again.
+ * 2. Returns ARCHIVE_EOF if decompression has been completed.
+ * 3. Returns ARCHIVE_FAILED if an error occurred; compressed data
+ * is broken or you do not set 'last' flag properly.
+ */
+#define ST_RD_TRANSLATION 0
+#define ST_RD_TRANSLATION_SIZE 1
+#define ST_RD_BLOCK_TYPE 2
+#define ST_RD_BLOCK_SIZE 3
+#define ST_RD_R0 4
+#define ST_RD_R1 5
+#define ST_RD_R2 6
+#define ST_COPY_UNCOMP1 7
+#define ST_COPY_UNCOMP2 8
+#define ST_RD_ALIGNED_OFFSET 9
+#define ST_RD_VERBATIM 10
+#define ST_RD_PRE_MAIN_TREE_256 11
+#define ST_MAIN_TREE_256 12
+#define ST_RD_PRE_MAIN_TREE_REM 13
+#define ST_MAIN_TREE_REM 14
+#define ST_RD_PRE_LENGTH_TREE 15
+#define ST_LENGTH_TREE 16
+#define ST_MAIN 17
+#define ST_LENGTH 18
+#define ST_OFFSET 19
+#define ST_REAL_POS 20
+#define ST_COPY 21
+
+static int
+lzx_decode(struct lzx_stream *strm, int last)
+{
+ struct lzx_dec *ds = strm->ds;
+ int64_t avail_in;
+ int r;
+
+ if (ds->error)
+ return (ds->error);
+
+ avail_in = strm->avail_in;
+ lzx_br_fixup(strm, &(ds->br));
+ do {
+ if (ds->state < ST_MAIN)
+ r = lzx_read_blocks(strm, last);
+ else {
+ int64_t bytes_written = strm->avail_out;
+ r = lzx_decode_blocks(strm, last);
+ bytes_written -= strm->avail_out;
+ strm->next_out += bytes_written;
+ strm->total_out += bytes_written;
+ }
+ } while (r == 100);
+ strm->total_in += avail_in - strm->avail_in;
+ return (r);
+}
+
+static int
+lzx_read_blocks(struct lzx_stream *strm, int last)
+{
+ struct lzx_dec *ds = strm->ds;
+ struct lzx_br *br = &(ds->br);
+ int i, r;
+
+ for (;;) {
+ switch (ds->state) {
+ case ST_RD_TRANSLATION:
+ if (!lzx_br_read_ahead(strm, br, 1)) {
+ ds->state = ST_RD_TRANSLATION;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ ds->translation = lzx_br_bits(br, 1);
+ lzx_br_consume(br, 1);
+ /* FALL THROUGH */
+ case ST_RD_TRANSLATION_SIZE:
+ if (ds->translation) {
+ if (!lzx_br_read_ahead(strm, br, 32)) {
+ ds->state = ST_RD_TRANSLATION_SIZE;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ ds->translation_size = lzx_br_bits(br, 16);
+ lzx_br_consume(br, 16);
+ ds->translation_size <<= 16;
+ ds->translation_size |= lzx_br_bits(br, 16);
+ lzx_br_consume(br, 16);
+ }
+ /* FALL THROUGH */
+ case ST_RD_BLOCK_TYPE:
+ if (!lzx_br_read_ahead(strm, br, 3)) {
+ ds->state = ST_RD_BLOCK_TYPE;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ ds->block_type = lzx_br_bits(br, 3);
+ lzx_br_consume(br, 3);
+ /* Check a block type. */
+ switch (ds->block_type) {
+ case VERBATIM_BLOCK:
+ case ALIGNED_OFFSET_BLOCK:
+ case UNCOMPRESSED_BLOCK:
+ break;
+ default:
+ goto failed;/* Invalid */
+ }
+ /* FALL THROUGH */
+ case ST_RD_BLOCK_SIZE:
+ if (!lzx_br_read_ahead(strm, br, 24)) {
+ ds->state = ST_RD_BLOCK_SIZE;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ ds->block_size = lzx_br_bits(br, 8);
+ lzx_br_consume(br, 8);
+ ds->block_size <<= 16;
+ ds->block_size |= lzx_br_bits(br, 16);
+ lzx_br_consume(br, 16);
+ if (ds->block_size == 0)
+ goto failed;
+ ds->block_bytes_avail = ds->block_size;
+ if (ds->block_type != UNCOMPRESSED_BLOCK) {
+ if (ds->block_type == VERBATIM_BLOCK)
+ ds->state = ST_RD_VERBATIM;
+ else
+ ds->state = ST_RD_ALIGNED_OFFSET;
+ break;
+ }
+ /*
+ * Handle an Uncompressed Block.
+ */
+ /* Skip padding to align following field on
+ * 16-bit boundary. */
+ if (br->cache_avail == 32 || br->cache_avail == 16)
+ lzx_br_consume(br, 16);
+ else
+ lzx_br_consume_unalined_bits(br);
+ /* Preparation to read repeated offsets R0,R1 and R2. */
+ ds->rbytes_avail = 0;
+ ds->state = ST_RD_R0;
+ /* FALL THROUGH */
+ case ST_RD_R0:
+ case ST_RD_R1:
+ case ST_RD_R2:
+ do {
+ uint16_t u16;
+ /* Drain bits in the cache buffer of
+ * bit-stream. */
+ if (lzx_br_has(br, 32)) {
+ u16 = lzx_br_bits(br, 16);
+ lzx_br_consume(br, 16);
+ archive_le16enc(ds->rbytes, u16);
+ u16 = lzx_br_bits(br, 16);
+ lzx_br_consume(br, 16);
+ archive_le16enc(ds->rbytes+2, u16);
+ ds->rbytes_avail = 4;
+ } else if (lzx_br_has(br, 16)) {
+ u16 = lzx_br_bits(br, 16);
+ lzx_br_consume(br, 16);
+ archive_le16enc(ds->rbytes, u16);
+ ds->rbytes_avail = 2;
+ } else
+ ds->rbytes_avail = 0;
+ if (ds->rbytes_avail < 4 && ds->br.have_odd) {
+ ds->rbytes[ds->rbytes_avail++] =
+ ds->br.odd;
+ ds->br.have_odd = 0;
+ }
+ while (ds->rbytes_avail < 4) {
+ if (strm->avail_in <= 0) {
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ ds->rbytes[ds->rbytes_avail++] =
+ *strm->next_in++;
+ strm->avail_in--;
+ }
+ if (ds->state == ST_RD_R0) {
+ ds->r0 = archive_le32dec(ds->rbytes);
+ if (ds->r0 < 0)
+ goto failed;
+ ds->state = ST_RD_R1;
+ } else if (ds->state == ST_RD_R1) {
+ ds->r1 = archive_le32dec(ds->rbytes);
+ if (ds->r1 < 0)
+ goto failed;
+ ds->state = ST_RD_R2;
+ } else if (ds->state == ST_RD_R2) {
+ ds->r2 = archive_le32dec(ds->rbytes);
+ if (ds->r2 < 0)
+ goto failed;
+ /* We've gotten all repeated offsets. */
+ ds->state = ST_COPY_UNCOMP1;
+ }
+ } while (ds->state != ST_COPY_UNCOMP1);
+ /* FALL THROUGH */
+ case ST_COPY_UNCOMP1:
+ /*
+ * Copy bytes form next_in to next_out directly.
+ */
+ while (ds->block_bytes_avail) {
+ unsigned char *d;
+ int l,ll;
+
+ if (strm->avail_out <= 0)
+ /* Output buffer is empty. */
+ return (ARCHIVE_OK);
+ if (strm->avail_in <= 0) {
+ /* Input buffer is empty. */
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ l = ds->block_bytes_avail;
+ if (l > ds->w_size - ds->w_pos)
+ l = ds->w_size - ds->w_pos;
+ if (l > strm->avail_out)
+ l = (int)strm->avail_out;
+ if (l > strm->avail_in)
+ l = (int)strm->avail_in;
+ ll = l;
+ d = &(ds->w_buff[ds->w_pos]);
+ while (--l >= 0) {
+ *strm->next_out++ = *strm->next_in;
+ *d++ = *strm->next_in++;
+ }
+ strm->avail_out -= ll;
+ strm->total_out += ll;
+ strm->avail_in -= ll;
+ ds->w_pos = (ds->w_pos + ll) & ds->w_mask;
+ ds->block_bytes_avail -= ll;
+ }
+ /* FALL THROUGH */
+ case ST_COPY_UNCOMP2:
+ /* Re-align; skip padding byte. */
+ if (ds->block_size & 1) {
+ if (strm->avail_in <= 0) {
+ /* Input buffer is empty. */
+ ds->state = ST_COPY_UNCOMP2;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ strm->next_in++;
+ strm->avail_in --;
+ }
+ /* This block ended. */
+ ds->state = ST_RD_BLOCK_TYPE;
+ return (ARCHIVE_EOF);
+ /********************/
+ case ST_RD_ALIGNED_OFFSET:
+ /*
+ * Read Aligned offset tree.
+ */
+ if (!lzx_br_read_ahead(strm, br, 3 * ds->at.len_size)) {
+ ds->state = ST_RD_ALIGNED_OFFSET;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ memset(ds->at.freq, 0, sizeof(ds->at.freq));
+ for (i = 0; i < ds->at.len_size; i++) {
+ ds->at.bitlen[i] = lzx_br_bits(br, 3);
+ ds->at.freq[ds->at.bitlen[i]]++;
+ lzx_br_consume(br, 3);
+ }
+ if (!lzx_make_huffman_table(&ds->at))
+ goto failed;
+ /* FALL THROUGH */
+ case ST_RD_VERBATIM:
+ ds->loop = 0;
+ /* FALL THROUGH */
+ case ST_RD_PRE_MAIN_TREE_256:
+ /*
+ * Read Pre-tree for first 256 elements of main tree.
+ */
+ if (!lzx_read_pre_tree(strm)) {
+ ds->state = ST_RD_PRE_MAIN_TREE_256;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ if (!lzx_make_huffman_table(&ds->pt))
+ goto failed;
+ ds->loop = 0;
+ /* FALL THROUGH */
+ case ST_MAIN_TREE_256:
+ /*
+ * Get path lengths of first 256 elements of main tree.
+ */
+ r = lzx_read_bitlen(strm, &ds->mt, 256);
+ if (r < 0)
+ goto failed;
+ else if (!r) {
+ ds->state = ST_MAIN_TREE_256;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ ds->loop = 0;
+ /* FALL THROUGH */
+ case ST_RD_PRE_MAIN_TREE_REM:
+ /*
+ * Read Pre-tree for remaining elements of main tree.
+ */
+ if (!lzx_read_pre_tree(strm)) {
+ ds->state = ST_RD_PRE_MAIN_TREE_REM;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ if (!lzx_make_huffman_table(&ds->pt))
+ goto failed;
+ ds->loop = 256;
+ /* FALL THROUGH */
+ case ST_MAIN_TREE_REM:
+ /*
+ * Get path lengths of remaining elements of main tree.
+ */
+ r = lzx_read_bitlen(strm, &ds->mt, -1);
+ if (r < 0)
+ goto failed;
+ else if (!r) {
+ ds->state = ST_MAIN_TREE_REM;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ if (!lzx_make_huffman_table(&ds->mt))
+ goto failed;
+ ds->loop = 0;
+ /* FALL THROUGH */
+ case ST_RD_PRE_LENGTH_TREE:
+ /*
+ * Read Pre-tree for remaining elements of main tree.
+ */
+ if (!lzx_read_pre_tree(strm)) {
+ ds->state = ST_RD_PRE_LENGTH_TREE;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ if (!lzx_make_huffman_table(&ds->pt))
+ goto failed;
+ ds->loop = 0;
+ /* FALL THROUGH */
+ case ST_LENGTH_TREE:
+ /*
+ * Get path lengths of remaining elements of main tree.
+ */
+ r = lzx_read_bitlen(strm, &ds->lt, -1);
+ if (r < 0)
+ goto failed;
+ else if (!r) {
+ ds->state = ST_LENGTH_TREE;
+ if (last)
+ goto failed;
+ return (ARCHIVE_OK);
+ }
+ if (!lzx_make_huffman_table(&ds->lt))
+ goto failed;
+ ds->state = ST_MAIN;
+ return (100);
+ }
+ }
+failed:
+ return (ds->error = ARCHIVE_FAILED);
+}
+
+static int
+lzx_decode_blocks(struct lzx_stream *strm, int last)
+{
+ struct lzx_dec *ds = strm->ds;
+ struct lzx_br bre = ds->br;
+ struct huffman *at = &(ds->at), *lt = &(ds->lt), *mt = &(ds->mt);
+ const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;
+ unsigned char *outp = strm->next_out;
+ unsigned char *endp = outp + strm->avail_out;
+ unsigned char *w_buff = ds->w_buff;
+ unsigned char *at_bitlen = at->bitlen;
+ unsigned char *lt_bitlen = lt->bitlen;
+ unsigned char *mt_bitlen = mt->bitlen;
+ size_t block_bytes_avail = ds->block_bytes_avail;
+ int at_max_bits = at->max_bits;
+ int lt_max_bits = lt->max_bits;
+ int mt_max_bits = mt->max_bits;
+ int c, copy_len = ds->copy_len, copy_pos = ds->copy_pos;
+ int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
+ int length_header = ds->length_header;
+ int offset_bits = ds->offset_bits;
+ int position_slot = ds->position_slot;
+ int r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;
+ int state = ds->state;
+ char block_type = ds->block_type;
+
+ for (;;) {
+ switch (state) {
+ case ST_MAIN:
+ for (;;) {
+ if (block_bytes_avail == 0) {
+ /* This block ended. */
+ ds->state = ST_RD_BLOCK_TYPE;
+ ds->br = bre;
+ ds->block_bytes_avail =
+ block_bytes_avail;
+ ds->copy_len = copy_len;
+ ds->copy_pos = copy_pos;
+ ds->length_header = length_header;
+ ds->position_slot = position_slot;
+ ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
+ ds->w_pos = w_pos;
+ strm->avail_out = endp - outp;
+ return (ARCHIVE_EOF);
+ }
+ if (outp >= endp)
+ /* Output buffer is empty. */
+ goto next_data;
+
+ if (!lzx_br_read_ahead(strm, &bre,
+ mt_max_bits)) {
+ if (!last)
+ goto next_data;
+ /* Remaining bits are less than
+ * maximum bits(mt.max_bits) but maybe
+ * it still remains as much as we need,
+ * so we should try to use it with
+ * dummy bits. */
+ c = lzx_decode_huffman(mt,
+ lzx_br_bits_forced(
+ &bre, mt_max_bits));
+ lzx_br_consume(&bre, mt_bitlen[c]);
+ if (!lzx_br_has(&bre, 0))
+ goto failed;/* Over read. */
+ } else {
+ c = lzx_decode_huffman(mt,
+ lzx_br_bits(&bre, mt_max_bits));
+ lzx_br_consume(&bre, mt_bitlen[c]);
+ }
+ if (c > UCHAR_MAX)
+ break;
+ /*
+ * 'c' is exactly literal code.
+ */
+ /* Save a decoded code to reference it
+ * afterward. */
+ w_buff[w_pos] = c;
+ w_pos = (w_pos + 1) & w_mask;
+ /* Store the decoded code to output buffer. */
+ *outp++ = c;
+ block_bytes_avail--;
+ }
+ /*
+ * Get a match code, its length and offset.
+ */
+ c -= UCHAR_MAX + 1;
+ length_header = c & 7;
+ position_slot = c >> 3;
+ /* FALL THROUGH */
+ case ST_LENGTH:
+ /*
+ * Get a length.
+ */
+ if (length_header == 7) {
+ if (!lzx_br_read_ahead(strm, &bre,
+ lt_max_bits)) {
+ if (!last) {
+ state = ST_LENGTH;
+ goto next_data;
+ }
+ c = lzx_decode_huffman(lt,
+ lzx_br_bits_forced(
+ &bre, lt_max_bits));
+ lzx_br_consume(&bre, lt_bitlen[c]);
+ if (!lzx_br_has(&bre, 0))
+ goto failed;/* Over read. */
+ } else {
+ c = lzx_decode_huffman(lt,
+ lzx_br_bits(&bre, lt_max_bits));
+ lzx_br_consume(&bre, lt_bitlen[c]);
+ }
+ copy_len = c + 7 + 2;
+ } else
+ copy_len = length_header + 2;
+ if ((size_t)copy_len > block_bytes_avail)
+ goto failed;
+ /*
+ * Get an offset.
+ */
+ switch (position_slot) {
+ case 0: /* Use repeated offset 0. */
+ copy_pos = r0;
+ state = ST_REAL_POS;
+ continue;
+ case 1: /* Use repeated offset 1. */
+ copy_pos = r1;
+ /* Swap repeated offset. */
+ r1 = r0;
+ r0 = copy_pos;
+ state = ST_REAL_POS;
+ continue;
+ case 2: /* Use repeated offset 2. */
+ copy_pos = r2;
+ /* Swap repeated offset. */
+ r2 = r0;
+ r0 = copy_pos;
+ state = ST_REAL_POS;
+ continue;
+ default:
+ offset_bits =
+ pos_tbl[position_slot].footer_bits;
+ break;
+ }
+ /* FALL THROUGH */
+ case ST_OFFSET:
+ /*
+ * Get the offset, which is a distance from
+ * current window position.
+ */
+ if (block_type == ALIGNED_OFFSET_BLOCK &&
+ offset_bits >= 3) {
+ int offbits = offset_bits - 3;
+
+ if (!lzx_br_read_ahead(strm, &bre, offbits)) {
+ state = ST_OFFSET;
+ if (last)
+ goto failed;
+ goto next_data;
+ }
+ copy_pos = lzx_br_bits(&bre, offbits) << 3;
+
+ /* Get an aligned number. */
+ if (!lzx_br_read_ahead(strm, &bre,
+ offbits + at_max_bits)) {
+ if (!last) {
+ state = ST_OFFSET;
+ goto next_data;
+ }
+ lzx_br_consume(&bre, offbits);
+ c = lzx_decode_huffman(at,
+ lzx_br_bits_forced(&bre,
+ at_max_bits));
+ lzx_br_consume(&bre, at_bitlen[c]);
+ if (!lzx_br_has(&bre, 0))
+ goto failed;/* Over read. */
+ } else {
+ lzx_br_consume(&bre, offbits);
+ c = lzx_decode_huffman(at,
+ lzx_br_bits(&bre, at_max_bits));
+ lzx_br_consume(&bre, at_bitlen[c]);
+ }
+ /* Add an aligned number. */
+ copy_pos += c;
+ } else {
+ if (!lzx_br_read_ahead(strm, &bre,
+ offset_bits)) {
+ state = ST_OFFSET;
+ if (last)
+ goto failed;
+ goto next_data;
+ }
+ copy_pos = lzx_br_bits(&bre, offset_bits);
+ lzx_br_consume(&bre, offset_bits);
+ }
+ copy_pos += pos_tbl[position_slot].base -2;
+
+ /* Update repeated offset LRU queue. */
+ r2 = r1;
+ r1 = r0;
+ r0 = copy_pos;
+ /* FALL THROUGH */
+ case ST_REAL_POS:
+ /*
+ * Compute a real position in window.
+ */
+ copy_pos = (w_pos - copy_pos) & w_mask;
+ /* FALL THROUGH */
+ case ST_COPY:
+ /*
+ * Copy several bytes as extracted data from the window
+ * into the output buffer.
+ */
+ for (;;) {
+ const unsigned char *s;
+ int l;
+
+ l = copy_len;
+ if (copy_pos > w_pos) {
+ if (l > w_size - copy_pos)
+ l = w_size - copy_pos;
+ } else {
+ if (l > w_size - w_pos)
+ l = w_size - w_pos;
+ }
+ if (outp + l >= endp)
+ l = endp - outp;
+ s = w_buff + copy_pos;
+ if (l >= 8 && ((copy_pos + l < w_pos)
+ || (w_pos + l < copy_pos))) {
+ memcpy(w_buff + w_pos, s, l);
+ memcpy(outp, s, l);
+ } else {
+ unsigned char *d;
+ int li;
+
+ d = w_buff + w_pos;
+ for (li = 0; li < l; li++)
+ outp[li] = d[li] = s[li];
+ }
+ outp += l;
+ copy_pos = (copy_pos + l) & w_mask;
+ w_pos = (w_pos + l) & w_mask;
+ block_bytes_avail -= l;
+ if (copy_len <= l)
+ /* A copy of current pattern ended. */
+ break;
+ copy_len -= l;
+ if (outp >= endp) {
+ /* Output buffer is empty. */
+ state = ST_COPY;
+ goto next_data;
+ }
+ }
+ state = ST_MAIN;
+ break;
+ }
+ }
+failed:
+ return (ds->error = ARCHIVE_FAILED);
+next_data:
+ ds->br = bre;
+ ds->block_bytes_avail = block_bytes_avail;
+ ds->copy_len = copy_len;
+ ds->copy_pos = copy_pos;
+ ds->length_header = length_header;
+ ds->offset_bits = offset_bits;
+ ds->position_slot = position_slot;
+ ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
+ ds->state = state;
+ ds->w_pos = w_pos;
+ strm->avail_out = endp - outp;
+ return (ARCHIVE_OK);
+}
+
+static int
+lzx_read_pre_tree(struct lzx_stream *strm)
+{
+ struct lzx_dec *ds = strm->ds;
+ struct lzx_br *br = &(ds->br);
+ int i;
+
+ if (ds->loop == 0)
+ memset(ds->pt.freq, 0, sizeof(ds->pt.freq));
+ for (i = ds->loop; i < ds->pt.len_size; i++) {
+ if (!lzx_br_read_ahead(strm, br, 4)) {
+ ds->loop = i;
+ return (0);
+ }
+ ds->pt.bitlen[i] = lzx_br_bits(br, 4);
+ ds->pt.freq[ds->pt.bitlen[i]]++;
+ lzx_br_consume(br, 4);
+ }
+ ds->loop = i;
+ return (1);
+}
+
+/*
+ * Read a bunch of bit-lengths from pre-tree.
+ */
+static int
+lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, int end)
+{
+ struct lzx_dec *ds = strm->ds;
+ struct lzx_br *br = &(ds->br);
+ int c, i, j, ret, same;
+ unsigned rbits;
+
+ i = ds->loop;
+ if (i == 0)
+ memset(d->freq, 0, sizeof(d->freq));
+ ret = 0;
+ if (end < 0)
+ end = d->len_size;
+ while (i < end) {
+ ds->loop = i;
+ if (!lzx_br_read_ahead(strm, br, ds->pt.max_bits))
+ goto getdata;
+ rbits = lzx_br_bits(br, ds->pt.max_bits);
+ c = lzx_decode_huffman(&(ds->pt), rbits);
+ switch (c) {
+ case 17:/* several zero lengths, from 4 to 19. */
+ if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+4))
+ goto getdata;
+ lzx_br_consume(br, ds->pt.bitlen[c]);
+ same = lzx_br_bits(br, 4) + 4;
+ if (i + same > end)
+ return (-1);/* Invalid */
+ lzx_br_consume(br, 4);
+ for (j = 0; j < same; j++)
+ d->bitlen[i++] = 0;
+ break;
+ case 18:/* many zero lengths, from 20 to 51. */
+ if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+5))
+ goto getdata;
+ lzx_br_consume(br, ds->pt.bitlen[c]);
+ same = lzx_br_bits(br, 5) + 20;
+ if (i + same > end)
+ return (-1);/* Invalid */
+ lzx_br_consume(br, 5);
+ memset(d->bitlen + i, 0, same);
+ i += same;
+ break;
+ case 19:/* a few same lengths. */
+ if (!lzx_br_read_ahead(strm, br,
+ ds->pt.bitlen[c]+1+ds->pt.max_bits))
+ goto getdata;
+ lzx_br_consume(br, ds->pt.bitlen[c]);
+ same = lzx_br_bits(br, 1) + 4;
+ if (i + same > end)
+ return (-1);
+ lzx_br_consume(br, 1);
+ rbits = lzx_br_bits(br, ds->pt.max_bits);
+ c = lzx_decode_huffman(&(ds->pt), rbits);
+ lzx_br_consume(br, ds->pt.bitlen[c]);
+ c = (d->bitlen[i] - c + 17) % 17;
+ if (c < 0)
+ return (-1);/* Invalid */
+ for (j = 0; j < same; j++)
+ d->bitlen[i++] = c;
+ d->freq[c] += same;
+ break;
+ default:
+ lzx_br_consume(br, ds->pt.bitlen[c]);
+ c = (d->bitlen[i] - c + 17) % 17;
+ if (c < 0)
+ return (-1);/* Invalid */
+ d->freq[c]++;
+ d->bitlen[i++] = c;
+ break;
+ }
+ }
+ ret = 1;
+getdata:
+ ds->loop = i;
+ return (ret);
+}
+
+static int
+lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
+{
+ int bits;
+
+ if (hf->bitlen == NULL || hf->len_size != (int)len_size) {
+ free(hf->bitlen);
+ hf->bitlen = calloc(len_size, sizeof(hf->bitlen[0]));
+ if (hf->bitlen == NULL)
+ return (ARCHIVE_FATAL);
+ hf->len_size = len_size;
+ } else
+ memset(hf->bitlen, 0, len_size * sizeof(hf->bitlen[0]));
+ if (hf->tbl == NULL) {
+ if (tbl_bits < HTBL_BITS)
+ bits = tbl_bits;
+ else
+ bits = HTBL_BITS;
+ hf->tbl = malloc((1 << bits) * sizeof(hf->tbl[0]));
+ if (hf->tbl == NULL)
+ return (ARCHIVE_FATAL);
+ hf->tbl_bits = tbl_bits;
+ }
+ if (hf->tree == NULL && tbl_bits > HTBL_BITS) {
+ hf->tree_avail = 1 << (tbl_bits - HTBL_BITS + 4);
+ hf->tree = malloc(hf->tree_avail * sizeof(hf->tree[0]));
+ if (hf->tree == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ return (ARCHIVE_OK);
+}
+
+static void
+lzx_huffman_free(struct huffman *hf)
+{
+ free(hf->bitlen);
+ free(hf->tbl);
+ free(hf->tree);
+}
+
+/*
+ * Make a huffman coding table.
+ */
+static int
+lzx_make_huffman_table(struct huffman *hf)
+{
+ uint16_t *tbl;
+ const unsigned char *bitlen;
+ int bitptn[17], weight[17];
+ int i, maxbits = 0, ptn, tbl_size, w;
+ int diffbits, len_avail;
+
+ /*
+ * Initialize bit patterns.
+ */
+ ptn = 0;
+ for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {
+ bitptn[i] = ptn;
+ weight[i] = w;
+ if (hf->freq[i]) {
+ ptn += hf->freq[i] * w;
+ maxbits = i;
+ }
+ }
+ if ((ptn & 0xffff) != 0 || maxbits > hf->tbl_bits)
+ return (0);/* Invalid */
+
+ hf->max_bits = maxbits;
+
+ /*
+ * Cut out extra bits which we won't house in the table.
+ * This preparation reduces the same calculation in the for-loop
+ * making the table.
+ */
+ if (maxbits < 16) {
+ int ebits = 16 - maxbits;
+ for (i = 1; i <= maxbits; i++) {
+ bitptn[i] >>= ebits;
+ weight[i] >>= ebits;
+ }
+ }
+ if (maxbits > HTBL_BITS) {
+ int htbl_max;
+ uint16_t *p;
+
+ diffbits = maxbits - HTBL_BITS;
+ for (i = 1; i <= HTBL_BITS; i++) {
+ bitptn[i] >>= diffbits;
+ weight[i] >>= diffbits;
+ }
+ htbl_max = bitptn[HTBL_BITS] +
+ weight[HTBL_BITS] * hf->freq[HTBL_BITS];
+ p = &(hf->tbl[htbl_max]);
+ while (p < &hf->tbl[1U<<HTBL_BITS])
+ *p++ = 0;
+ } else
+ diffbits = 0;
+ hf->shift_bits = diffbits;
+
+ /*
+ * Make the table.
+ */
+ tbl_size = 1 << HTBL_BITS;
+ tbl = hf->tbl;
+ bitlen = hf->bitlen;
+ len_avail = hf->len_size;
+ hf->tree_used = 0;
+ for (i = 0; i < len_avail; i++) {
+ uint16_t *p;
+ int len, cnt;
+ uint16_t bit;
+ int extlen;
+ struct htree_t *ht;
+
+ if (bitlen[i] == 0)
+ continue;
+ /* Get a bit pattern */
+ len = bitlen[i];
+ ptn = bitptn[len];
+ cnt = weight[len];
+ if (len <= HTBL_BITS) {
+ /* Calculate next bit pattern */
+ if ((bitptn[len] = ptn + cnt) > tbl_size)
+ return (0);/* Invalid */
+ /* Update the table */
+ p = &(tbl[ptn]);
+ while (--cnt >= 0)
+ p[cnt] = (uint16_t)i;
+ continue;
+ }
+
+ /*
+ * A bit length is too big to be housed to a direct table,
+ * so we use a tree model for its extra bits.
+ */
+ bitptn[len] = ptn + cnt;
+ bit = 1U << (diffbits -1);
+ extlen = len - HTBL_BITS;
+
+ p = &(tbl[ptn >> diffbits]);
+ if (*p == 0) {
+ *p = len_avail + hf->tree_used;
+ ht = &(hf->tree[hf->tree_used++]);
+ if (hf->tree_used > hf->tree_avail)
+ return (0);/* Invalid */
+ ht->left = 0;
+ ht->right = 0;
+ } else {
+ if (*p < len_avail ||
+ *p >= (len_avail + hf->tree_used))
+ return (0);/* Invalid */
+ ht = &(hf->tree[*p - len_avail]);
+ }
+ while (--extlen > 0) {
+ if (ptn & bit) {
+ if (ht->left < len_avail) {
+ ht->left = len_avail + hf->tree_used;
+ ht = &(hf->tree[hf->tree_used++]);
+ if (hf->tree_used > hf->tree_avail)
+ return (0);/* Invalid */
+ ht->left = 0;
+ ht->right = 0;
+ } else {
+ ht = &(hf->tree[ht->left - len_avail]);
+ }
+ } else {
+ if (ht->right < len_avail) {
+ ht->right = len_avail + hf->tree_used;
+ ht = &(hf->tree[hf->tree_used++]);
+ if (hf->tree_used > hf->tree_avail)
+ return (0);/* Invalid */
+ ht->left = 0;
+ ht->right = 0;
+ } else {
+ ht = &(hf->tree[ht->right - len_avail]);
+ }
+ }
+ bit >>= 1;
+ }
+ if (ptn & bit) {
+ if (ht->left != 0)
+ return (0);/* Invalid */
+ ht->left = (uint16_t)i;
+ } else {
+ if (ht->right != 0)
+ return (0);/* Invalid */
+ ht->right = (uint16_t)i;
+ }
+ }
+ return (1);
+}
+
+static int
+lzx_decode_huffman_tree(struct huffman *hf, unsigned rbits, int c)
+{
+ struct htree_t *ht;
+ int extlen;
+
+ ht = hf->tree;
+ extlen = hf->shift_bits;
+ while (c >= hf->len_size) {
+ c -= hf->len_size;
+ if (extlen-- <= 0 || c >= hf->tree_used)
+ return (0);
+ if (rbits & (1U << extlen))
+ c = ht[c].left;
+ else
+ c = ht[c].right;
+ }
+ return (c);
+}
+
+static inline int
+lzx_decode_huffman(struct huffman *hf, unsigned rbits)
+{
+ int c;
+ /*
+ * At first search an index table for a bit pattern.
+ * If it fails, search a huffman tree for.
+ */
+ c = hf->tbl[rbits >> hf->shift_bits];
+ if (c < hf->len_size)
+ return (c);
+ /* This bit pattern needs to be found out at a huffman tree. */
+ return (lzx_decode_huffman_tree(hf, rbits, c));
+}
+
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_format_lha.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_format_lha.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,2747 @@
+/*-
+ * Copyright (c) 2008-2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_entry_locale.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+#include "archive_endian.h"
+
+
+#define MAXMATCH 256 /* Maximum match length. */
+#define MINMATCH 3 /* Minimum match length. */
+/*
+ * Literal table format:
+ * +0 +256 +510
+ * +---------------+-------------------------+
+ * | literal code | match length |
+ * | 0 ... 255 | MINMATCH ... MAXMATCH |
+ * +---------------+-------------------------+
+ * <--- LT_BITLEN_SIZE --->
+ */
+/* Literal table size. */
+#define LT_BITLEN_SIZE (UCHAR_MAX + 1 + MAXMATCH - MINMATCH + 1)
+/* Position table size.
+ * Note: this used for both position table and pre literal table.*/
+#define PT_BITLEN_SIZE (3 + 16)
+
+struct lzh_dec {
+ /* Decoding status. */
+ int state;
+
+ /*
+ * Window to see last 8Ki(lh5),32Ki(lh6),64Ki(lh7) bytes of decoded
+ * data.
+ */
+ int w_size;
+ int w_mask;
+ /* Window buffer, which is a loop buffer. */
+ unsigned char *w_buff;
+ /* The insert position to the window. */
+ int w_pos;
+ /* The position where we can copy decoded code from the window. */
+ int copy_pos;
+ /* The length how many bytes we can copy decoded code from
+ * the window. */
+ int copy_len;
+ /* The remaining bytes that we have not copied decoded data from
+ * the window to an output buffer. */
+ int w_remaining;
+
+ /*
+ * Bit stream reader.
+ */
+ struct lzh_br {
+#define CACHE_TYPE uint64_t
+#define CACHE_BITS (8 * sizeof(CACHE_TYPE))
+ /* Cache buffer. */
+ CACHE_TYPE cache_buffer;
+ /* Indicates how many bits avail in cache_buffer. */
+ int cache_avail;
+ } br;
+
+ /*
+ * Huffman coding.
+ */
+ struct huffman {
+ int len_size;
+ int len_avail;
+ int len_bits;
+ int freq[17];
+ unsigned char *bitlen;
+
+ /*
+ * Use a index table. It's faster than searching a huffman
+ * coding tree, which is a binary tree. But a use of a large
+ * index table causes L1 cache read miss many times.
+ */
+#define HTBL_BITS 10
+ int max_bits;
+ int shift_bits;
+ int tbl_bits;
+ int tree_used;
+ int tree_avail;
+ /* Direct access table. */
+ uint16_t *tbl;
+ /* Binary tree table for extra bits over the direct access. */
+ struct htree_t {
+ uint16_t left;
+ uint16_t right;
+ } *tree;
+ } lt, pt;
+
+ int blocks_avail;
+ int pos_pt_len_size;
+ int pos_pt_len_bits;
+ int literal_pt_len_size;
+ int literal_pt_len_bits;
+ int reading_position;
+ int loop;
+ int error;
+};
+
+struct lzh_stream {
+ const unsigned char *next_in;
+ int64_t avail_in;
+ int64_t total_in;
+ unsigned char *next_out;
+ int64_t avail_out;
+ int64_t total_out;
+ struct lzh_dec *ds;
+};
+
+struct lha {
+ /* entry_bytes_remaining is the number of bytes we expect. */
+ int64_t entry_offset;
+ int64_t entry_bytes_remaining;
+ int64_t entry_unconsumed;
+ uint16_t entry_crc_calculated;
+
+ size_t header_size; /* header size */
+ unsigned char level; /* header level */
+ char method[3]; /* compress type */
+ int64_t compsize; /* compressed data size */
+ int64_t origsize; /* original file size */
+ int setflag;
+#define BIRTHTIME_IS_SET 1
+#define ATIME_IS_SET 2
+#define UNIX_MODE_IS_SET 4
+#define CRC_IS_SET 8
+ time_t birthtime;
+ long birthtime_tv_nsec;
+ time_t mtime;
+ long mtime_tv_nsec;
+ time_t atime;
+ long atime_tv_nsec;
+ mode_t mode;
+ int64_t uid;
+ int64_t gid;
+ struct archive_string uname;
+ struct archive_string gname;
+ uint16_t header_crc;
+ uint16_t crc;
+ struct archive_string_conv *sconv;
+ struct archive_string_conv *opt_sconv;
+
+ struct archive_string dirname;
+ struct archive_string filename;
+ struct archive_wstring ws;
+
+ unsigned char dos_attr;
+
+ /* Flag to mark progress that an archive was read their first header.*/
+ char found_first_header;
+ /* Flag to mark that indicates an empty directory. */
+ char directory;
+
+ /* Flags to mark progress of decompression. */
+ char decompress_init;
+ char end_of_entry;
+ char end_of_entry_cleanup;
+ char entry_is_compressed;
+
+ unsigned char *uncompressed_buffer;
+ size_t uncompressed_buffer_size;
+
+ char format_name[64];
+
+ struct lzh_stream strm;
+};
+
+/*
+ * LHA header common member offset.
+ */
+#define H_METHOD_OFFSET 2 /* Compress type. */
+#define H_ATTR_OFFSET 19 /* DOS attribute. */
+#define H_LEVEL_OFFSET 20 /* Header Level. */
+#define H_SIZE 22 /* Minimum header size. */
+
+static const uint16_t crc16tbl[256] = {
+ 0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
+ 0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
+ 0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
+ 0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
+ 0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
+ 0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
+ 0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
+ 0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
+ 0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
+ 0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
+ 0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
+ 0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
+ 0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
+ 0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
+ 0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
+ 0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
+ 0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
+ 0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
+ 0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
+ 0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
+ 0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
+ 0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
+ 0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
+ 0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
+ 0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
+ 0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
+ 0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
+ 0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
+ 0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
+ 0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
+ 0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
+ 0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
+};
+
+static int archive_read_format_lha_bid(struct archive_read *, int);
+static int archive_read_format_lha_options(struct archive_read *,
+ const char *, const char *);
+static int archive_read_format_lha_read_header(struct archive_read *,
+ struct archive_entry *);
+static int archive_read_format_lha_read_data(struct archive_read *,
+ const void **, size_t *, int64_t *);
+static int archive_read_format_lha_read_data_skip(struct archive_read *);
+static int archive_read_format_lha_cleanup(struct archive_read *);
+
+static void lha_replace_path_separator(struct lha *,
+ struct archive_entry *);
+static int lha_read_file_header_0(struct archive_read *, struct lha *);
+static int lha_read_file_header_1(struct archive_read *, struct lha *);
+static int lha_read_file_header_2(struct archive_read *, struct lha *);
+static int lha_read_file_header_3(struct archive_read *, struct lha *);
+static int lha_read_file_extended_header(struct archive_read *,
+ struct lha *, uint16_t *, int, size_t, size_t *);
+static size_t lha_check_header_format(const void *);
+static int lha_skip_sfx(struct archive_read *);
+static time_t lha_dos_time(const unsigned char *);
+static time_t lha_win_time(uint64_t, long *);
+static unsigned char lha_calcsum(unsigned char, const void *,
+ int, int);
+static int lha_parse_linkname(struct archive_string *,
+ struct archive_string *);
+static int lha_read_data_none(struct archive_read *, const void **,
+ size_t *, int64_t *);
+static int lha_read_data_lzh(struct archive_read *, const void **,
+ size_t *, int64_t *);
+static uint16_t lha_crc16(uint16_t, const void *, size_t);
+static int lzh_decode_init(struct lzh_stream *, const char *);
+static void lzh_decode_free(struct lzh_stream *);
+static int lzh_decode(struct lzh_stream *, int);
+static int lzh_br_fillup(struct lzh_stream *, struct lzh_br *);
+static int lzh_huffman_init(struct huffman *, size_t, int);
+static void lzh_huffman_free(struct huffman *);
+static int lzh_read_pt_bitlen(struct lzh_stream *, int start, int end);
+static int lzh_make_fake_table(struct huffman *, uint16_t);
+static int lzh_make_huffman_table(struct huffman *);
+static inline int lzh_decode_huffman(struct huffman *, unsigned);
+static int lzh_decode_huffman_tree(struct huffman *, unsigned, int);
+
+
+int
+archive_read_support_format_lha(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct lha *lha;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_format_lha");
+
+ lha = (struct lha *)calloc(1, sizeof(*lha));
+ if (lha == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate lha data");
+ return (ARCHIVE_FATAL);
+ }
+ archive_string_init(&lha->ws);
+
+ r = __archive_read_register_format(a,
+ lha,
+ "lha",
+ archive_read_format_lha_bid,
+ archive_read_format_lha_options,
+ archive_read_format_lha_read_header,
+ archive_read_format_lha_read_data,
+ archive_read_format_lha_read_data_skip,
+ archive_read_format_lha_cleanup);
+
+ if (r != ARCHIVE_OK)
+ free(lha);
+ return (ARCHIVE_OK);
+}
+
+static size_t
+lha_check_header_format(const void *h)
+{
+ const unsigned char *p = h;
+ size_t next_skip_bytes;
+
+ switch (p[H_METHOD_OFFSET+3]) {
+ /*
+ * "-lh0-" ... "-lh7-" "-lhd-"
+ * "-lzs-" "-lz5-"
+ */
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case 'd':
+ case 's':
+ next_skip_bytes = 4;
+
+ /* b0 == 0 means the end of an LHa archive file. */
+ if (p[0] == 0)
+ break;
+ if (p[H_METHOD_OFFSET] != '-' || p[H_METHOD_OFFSET+1] != 'l'
+ || p[H_METHOD_OFFSET+4] != '-')
+ break;
+
+ if (p[H_METHOD_OFFSET+2] == 'h') {
+ /* "-lh?-" */
+ if (p[H_METHOD_OFFSET+3] == 's')
+ break;
+ if (p[H_LEVEL_OFFSET] == 0)
+ return (0);
+ if (p[H_LEVEL_OFFSET] <= 3 && p[H_ATTR_OFFSET] == 0x20)
+ return (0);
+ }
+ if (p[H_METHOD_OFFSET+2] == 'z') {
+ /* LArc extensions: -lzs-,-lz4- and -lz5- */
+ if (p[H_LEVEL_OFFSET] != 0)
+ break;
+ if (p[H_METHOD_OFFSET+3] == 's'
+ || p[H_METHOD_OFFSET+3] == '4'
+ || p[H_METHOD_OFFSET+3] == '5')
+ return (0);
+ }
+ break;
+ case 'h': next_skip_bytes = 1; break;
+ case 'z': next_skip_bytes = 1; break;
+ case 'l': next_skip_bytes = 2; break;
+ case '-': next_skip_bytes = 3; break;
+ default : next_skip_bytes = 4; break;
+ }
+
+ return (next_skip_bytes);
+}
+
+static int
+archive_read_format_lha_bid(struct archive_read *a, int best_bid)
+{
+ const char *p;
+ const void *buff;
+ ssize_t bytes_avail, offset, window;
+ size_t next;
+
+ /* If there's already a better bid than we can ever
+ make, don't bother testing. */
+ if (best_bid > 30)
+ return (-1);
+
+ if ((p = __archive_read_ahead(a, H_SIZE, NULL)) == NULL)
+ return (-1);
+
+ if (lha_check_header_format(p) == 0)
+ return (30);
+
+ if (p[0] == 'M' && p[1] == 'Z') {
+ /* PE file */
+ offset = 0;
+ window = 4096;
+ while (offset < (1024 * 20)) {
+ buff = __archive_read_ahead(a, offset + window,
+ &bytes_avail);
+ if (buff == NULL) {
+ /* Remaining bytes are less than window. */
+ window >>= 1;
+ if (window < (H_SIZE + 3))
+ return (0);
+ continue;
+ }
+ p = (const char *)buff + offset;
+ while (p + H_SIZE < (const char *)buff + bytes_avail) {
+ if ((next = lha_check_header_format(p)) == 0)
+ return (30);
+ p += next;
+ }
+ offset = p - (const char *)buff;
+ }
+ }
+ return (0);
+}
+
+static int
+archive_read_format_lha_options(struct archive_read *a,
+ const char *key, const char *val)
+{
+ struct lha *lha;
+ int ret = ARCHIVE_FAILED;
+
+ lha = (struct lha *)(a->format->data);
+ if (strcmp(key, "hdrcharset") == 0) {
+ if (val == NULL || val[0] == 0)
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "lha: hdrcharset option needs a character-set name");
+ else {
+ lha->opt_sconv =
+ archive_string_conversion_from_charset(
+ &a->archive, val, 0);
+ if (lha->opt_sconv != NULL)
+ ret = ARCHIVE_OK;
+ else
+ ret = ARCHIVE_FATAL;
+ }
+ return (ret);
+ }
+
+ /* Note: The "warn" return is just to inform the options
+ * supervisor that we didn't handle it. It will generate
+ * a suitable error if no one used this option. */
+ return (ARCHIVE_WARN);
+}
+
+static int
+lha_skip_sfx(struct archive_read *a)
+{
+ const void *h;
+ const char *p, *q;
+ size_t next, skip;
+ ssize_t bytes, window;
+
+ window = 4096;
+ for (;;) {
+ h = __archive_read_ahead(a, window, &bytes);
+ if (h == NULL) {
+ /* Remaining bytes are less than window. */
+ window >>= 1;
+ if (window < (H_SIZE + 3))
+ goto fatal;
+ continue;
+ }
+ if (bytes < H_SIZE)
+ goto fatal;
+ p = h;
+ q = p + bytes;
+
+ /*
+ * Scan ahead until we find something that looks
+ * like the lha header.
+ */
+ while (p + H_SIZE < q) {
+ if ((next = lha_check_header_format(p)) == 0) {
+ skip = p - (const char *)h;
+ __archive_read_consume(a, skip);
+ return (ARCHIVE_OK);
+ }
+ p += next;
+ }
+ skip = p - (const char *)h;
+ __archive_read_consume(a, skip);
+ }
+fatal:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Couldn't find out LHa header");
+ return (ARCHIVE_FATAL);
+}
+
+static int
+truncated_error(struct archive_read *a)
+{
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated LHa header");
+ return (ARCHIVE_FATAL);
+}
+
+static int
+archive_read_format_lha_read_header(struct archive_read *a,
+ struct archive_entry *entry)
+{
+ struct archive_string linkname;
+ struct archive_string pathname;
+ struct lha *lha;
+ const unsigned char *p;
+ const char *signature;
+ int err;
+
+ a->archive.archive_format = ARCHIVE_FORMAT_LHA;
+ if (a->archive.archive_format_name == NULL)
+ a->archive.archive_format_name = "lha";
+
+ lha = (struct lha *)(a->format->data);
+ lha->decompress_init = 0;
+ lha->end_of_entry = 0;
+ lha->end_of_entry_cleanup = 0;
+ lha->entry_unconsumed = 0;
+
+ if ((p = __archive_read_ahead(a, H_SIZE, NULL)) == NULL) {
+ /*
+ * LHa archiver added 0 to the tail of its archive file as
+ * the mark of the end of the archive.
+ */
+ signature = __archive_read_ahead(a, sizeof(signature[0]), NULL);
+ if (signature == NULL || signature[0] == 0)
+ return (ARCHIVE_EOF);
+ return (truncated_error(a));
+ }
+
+ signature = (const char *)p;
+ if (lha->found_first_header == 0 &&
+ signature[0] == 'M' && signature[1] == 'Z') {
+ /* This is an executable? Must be self-extracting... */
+ err = lha_skip_sfx(a);
+ if (err < ARCHIVE_WARN)
+ return (err);
+
+ if ((p = __archive_read_ahead(a, sizeof(*p), NULL)) == NULL)
+ return (truncated_error(a));
+ signature = (const char *)p;
+ }
+ /* signature[0] == 0 means the end of an LHa archive file. */
+ if (signature[0] == 0)
+ return (ARCHIVE_EOF);
+
+ /*
+ * Check the header format and method type.
+ */
+ if (lha_check_header_format(p) != 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Bad LHa file");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* We've found the first header. */
+ lha->found_first_header = 1;
+ /* Set a default value and common data */
+ lha->header_size = 0;
+ lha->level = p[H_LEVEL_OFFSET];
+ lha->method[0] = p[H_METHOD_OFFSET+1];
+ lha->method[1] = p[H_METHOD_OFFSET+2];
+ lha->method[2] = p[H_METHOD_OFFSET+3];
+ if (memcmp(lha->method, "lhd", 3) == 0)
+ lha->directory = 1;
+ else
+ lha->directory = 0;
+ if (memcmp(lha->method, "lh0", 3) == 0 ||
+ memcmp(lha->method, "lz4", 3) == 0)
+ lha->entry_is_compressed = 0;
+ else
+ lha->entry_is_compressed = 1;
+
+ lha->compsize = 0;
+ lha->origsize = 0;
+ lha->setflag = 0;
+ lha->birthtime = 0;
+ lha->birthtime_tv_nsec = 0;
+ lha->mtime = 0;
+ lha->mtime_tv_nsec = 0;
+ lha->atime = 0;
+ lha->atime_tv_nsec = 0;
+ lha->mode = (lha->directory)? 0777 : 0666;
+ lha->uid = 0;
+ lha->gid = 0;
+ archive_string_empty(&lha->dirname);
+ archive_string_empty(&lha->filename);
+ lha->dos_attr = 0;
+ if (lha->opt_sconv != NULL)
+ lha->sconv = lha->opt_sconv;
+ else
+ lha->sconv = NULL;
+
+ switch (p[H_LEVEL_OFFSET]) {
+ case 0:
+ err = lha_read_file_header_0(a, lha);
+ break;
+ case 1:
+ err = lha_read_file_header_1(a, lha);
+ break;
+ case 2:
+ err = lha_read_file_header_2(a, lha);
+ break;
+ case 3:
+ err = lha_read_file_header_3(a, lha);
+ break;
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unsupported LHa header level %d", p[H_LEVEL_OFFSET]);
+ err = ARCHIVE_FATAL;
+ break;
+ }
+ if (err < ARCHIVE_WARN)
+ return (err);
+
+
+ if (!lha->directory && archive_strlen(&lha->filename) == 0)
+ /* The filename has not been set */
+ return (truncated_error(a));
+
+ /*
+ * Make a pathname from a dirname and a filename.
+ */
+ archive_string_concat(&lha->dirname, &lha->filename);
+ archive_string_init(&pathname);
+ archive_string_init(&linkname);
+ archive_string_copy(&pathname, &lha->dirname);
+
+ if ((lha->mode & AE_IFMT) == AE_IFLNK) {
+ /*
+ * Extract the symlink-name if it's included in the pathname.
+ */
+ if (!lha_parse_linkname(&linkname, &pathname)) {
+ /* We couldn't get the symlink-name. */
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unknown symlink-name");
+ archive_string_free(&pathname);
+ archive_string_free(&linkname);
+ return (ARCHIVE_FAILED);
+ }
+ } else {
+ /*
+ * Make sure a file-type is set.
+ * The mode has been overridden if it is in the extended data.
+ */
+ lha->mode = (lha->mode & ~AE_IFMT) |
+ ((lha->directory)? AE_IFDIR: AE_IFREG);
+ }
+ if ((lha->setflag & UNIX_MODE_IS_SET) == 0 &&
+ (lha->dos_attr & 1) != 0)
+ lha->mode &= ~(0222);/* read only. */
+
+ /*
+ * Set basic file parameters.
+ */
+ if (archive_entry_copy_pathname_l(entry, pathname.s,
+ pathname.length, lha->sconv) != 0) {
+ if (errno == ENOMEM) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for Pathname");
+ return (ARCHIVE_FATAL);
+ }
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Pathname cannot be converted "
+ "from %s to current locale.",
+ archive_string_conversion_charset_name(lha->sconv));
+ err = ARCHIVE_WARN;
+ }
+ archive_string_free(&pathname);
+ if (archive_strlen(&linkname) > 0) {
+ if (archive_entry_copy_symlink_l(entry, linkname.s,
+ linkname.length, lha->sconv) != 0) {
+ if (errno == ENOMEM) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for Linkname");
+ return (ARCHIVE_FATAL);
+ }
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Linkname cannot be converted "
+ "from %s to current locale.",
+ archive_string_conversion_charset_name(lha->sconv));
+ err = ARCHIVE_WARN;
+ }
+ } else
+ archive_entry_set_symlink(entry, NULL);
+ archive_string_free(&linkname);
+ /*
+ * When a header level is 0, there is a possibility that
+ * a pathname and a symlink has '\' character, a directory
+ * separator in DOS/Windows. So we should convert it to '/'.
+ */
+ if (p[H_LEVEL_OFFSET] == 0)
+ lha_replace_path_separator(lha, entry);
+
+ archive_entry_set_mode(entry, lha->mode);
+ archive_entry_set_uid(entry, lha->uid);
+ archive_entry_set_gid(entry, lha->gid);
+ if (archive_strlen(&lha->uname) > 0)
+ archive_entry_set_uname(entry, lha->uname.s);
+ if (archive_strlen(&lha->gname) > 0)
+ archive_entry_set_gname(entry, lha->gname.s);
+ if (lha->setflag & BIRTHTIME_IS_SET) {
+ archive_entry_set_birthtime(entry, lha->birthtime,
+ lha->birthtime_tv_nsec);
+ archive_entry_set_ctime(entry, lha->birthtime,
+ lha->birthtime_tv_nsec);
+ } else {
+ archive_entry_unset_birthtime(entry);
+ archive_entry_unset_ctime(entry);
+ }
+ archive_entry_set_mtime(entry, lha->mtime, lha->mtime_tv_nsec);
+ if (lha->setflag & ATIME_IS_SET)
+ archive_entry_set_atime(entry, lha->atime,
+ lha->atime_tv_nsec);
+ else
+ archive_entry_unset_atime(entry);
+ if (lha->directory || archive_entry_symlink(entry) != NULL)
+ archive_entry_unset_size(entry);
+ else
+ archive_entry_set_size(entry, lha->origsize);
+
+ /*
+ * Prepare variables used to read a file content.
+ */
+ lha->entry_bytes_remaining = lha->compsize;
+ lha->entry_offset = 0;
+ lha->entry_crc_calculated = 0;
+
+ /*
+ * This file does not have a content.
+ */
+ if (lha->directory || lha->compsize == 0)
+ lha->end_of_entry = 1;
+
+ sprintf(lha->format_name, "lha -%c%c%c-",
+ lha->method[0], lha->method[1], lha->method[2]);
+ a->archive.archive_format_name = lha->format_name;
+
+ return (err);
+}
+
+/*
+ * Replace a DOS path separator '\' by a character '/'.
+ * Some multi-byte character set have a character '\' in its second byte.
+ */
+static void
+lha_replace_path_separator(struct lha *lha, struct archive_entry *entry)
+{
+ const wchar_t *wp;
+ size_t i;
+
+ if ((wp = archive_entry_pathname_w(entry)) != NULL) {
+ archive_wstrcpy(&(lha->ws), wp);
+ for (i = 0; i < archive_strlen(&(lha->ws)); i++) {
+ if (lha->ws.s[i] == L'\\')
+ lha->ws.s[i] = L'/';
+ }
+ archive_entry_copy_pathname_w(entry, lha->ws.s);
+ }
+
+ if ((wp = archive_entry_symlink_w(entry)) != NULL) {
+ archive_wstrcpy(&(lha->ws), wp);
+ for (i = 0; i < archive_strlen(&(lha->ws)); i++) {
+ if (lha->ws.s[i] == L'\\')
+ lha->ws.s[i] = L'/';
+ }
+ archive_entry_copy_symlink_w(entry, lha->ws.s);
+ }
+}
+
+/*
+ * Header 0 format
+ *
+ * +0 +1 +2 +7 +11
+ * +---------------+----------+----------------+-------------------+
+ * |header size(*1)|header sum|compression type|compressed size(*2)|
+ * +---------------+----------+----------------+-------------------+
+ * <---------------------(*1)----------*
+ *
+ * +11 +15 +17 +19 +20 +21
+ * +-----------------+---------+---------+--------------+----------------+
+ * |uncompressed size|time(DOS)|date(DOS)|attribute(DOS)|header level(=0)|
+ * +-----------------+---------+---------+--------------+----------------+
+ * *--------------------------------(*1)---------------------------------*
+ *
+ * +21 +22 +22+(*3) +22+(*3)+2 +22+(*3)+2+(*4)
+ * +---------------+---------+----------+----------------+------------------+
+ * |name length(*3)|file name|file CRC16|extra header(*4)| compressed data |
+ * +---------------+---------+----------+----------------+------------------+
+ * <--(*3)-> <------(*2)------>
+ * *----------------------(*1)-------------------------->
+ *
+ */
+#define H0_HEADER_SIZE_OFFSET 0
+#define H0_HEADER_SUM_OFFSET 1
+#define H0_COMP_SIZE_OFFSET 7
+#define H0_ORIG_SIZE_OFFSET 11
+#define H0_DOS_TIME_OFFSET 15
+#define H0_NAME_LEN_OFFSET 21
+#define H0_FILE_NAME_OFFSET 22
+#define H0_FIXED_SIZE 24
+static int
+lha_read_file_header_0(struct archive_read *a, struct lha *lha)
+{
+ const unsigned char *p;
+ int extdsize, namelen;
+ unsigned char headersum, sum_calculated;
+
+ if ((p = __archive_read_ahead(a, H0_FIXED_SIZE, NULL)) == NULL)
+ return (truncated_error(a));
+ lha->header_size = p[H0_HEADER_SIZE_OFFSET] + 2;
+ headersum = p[H0_HEADER_SUM_OFFSET];
+ lha->compsize = archive_le32dec(p + H0_COMP_SIZE_OFFSET);
+ lha->origsize = archive_le32dec(p + H0_ORIG_SIZE_OFFSET);
+ lha->mtime = lha_dos_time(p + H0_DOS_TIME_OFFSET);
+ namelen = p[H0_NAME_LEN_OFFSET];
+ extdsize = (int)lha->header_size - H0_FIXED_SIZE - namelen;
+ if ((namelen > 221 || extdsize < 0) && extdsize != -2) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid LHa header");
+ return (ARCHIVE_FATAL);
+ }
+ if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL)
+ return (truncated_error(a));
+
+ archive_strncpy(&lha->filename, p + H0_FILE_NAME_OFFSET, namelen);
+ /* When extdsize == -2, A CRC16 value is not present in the header. */
+ if (extdsize >= 0) {
+ lha->crc = archive_le16dec(p + H0_FILE_NAME_OFFSET + namelen);
+ lha->setflag |= CRC_IS_SET;
+ }
+ sum_calculated = lha_calcsum(0, p, 2, lha->header_size - 2);
+
+ /* Read an extended header */
+ if (extdsize > 0) {
+ /* This extended data is set by 'LHa for UNIX' only.
+ * Maybe fixed size.
+ */
+ p += H0_FILE_NAME_OFFSET + namelen + 2;
+ if (p[0] == 'U' && extdsize == 12) {
+ /* p[1] is a minor version. */
+ lha->mtime = archive_le32dec(&p[2]);
+ lha->mode = archive_le16dec(&p[6]);
+ lha->uid = archive_le16dec(&p[8]);
+ lha->gid = archive_le16dec(&p[10]);
+ lha->setflag |= UNIX_MODE_IS_SET;
+ }
+ }
+ __archive_read_consume(a, lha->header_size);
+
+ if (sum_calculated != headersum) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "LHa header sum error");
+ return (ARCHIVE_FATAL);
+ }
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Header 1 format
+ *
+ * +0 +1 +2 +7 +11
+ * +---------------+----------+----------------+-------------+
+ * |header size(*1)|header sum|compression type|skip size(*2)|
+ * +---------------+----------+----------------+-------------+
+ * <---------------(*1)----------*
+ *
+ * +11 +15 +17 +19 +20 +21
+ * +-----------------+---------+---------+--------------+----------------+
+ * |uncompressed size|time(DOS)|date(DOS)|attribute(DOS)|header level(=1)|
+ * +-----------------+---------+---------+--------------+----------------+
+ * *-------------------------------(*1)----------------------------------*
+ *
+ * +21 +22 +22+(*3) +22+(*3)+2 +22+(*3)+3 +22+(*3)+3+(*4)
+ * +---------------+---------+----------+-----------+-----------+
+ * |name length(*3)|file name|file CRC16| creator |padding(*4)|
+ * +---------------+---------+----------+-----------+-----------+
+ * <--(*3)->
+ * *----------------------------(*1)----------------------------*
+ *
+ * +22+(*3)+3+(*4) +22+(*3)+3+(*4)+2 +22+(*3)+3+(*4)+2+(*5)
+ * +----------------+---------------------+------------------------+
+ * |next header size| extended header(*5) | compressed data |
+ * +----------------+---------------------+------------------------+
+ * *------(*1)-----> <--------------------(*2)-------------------->
+ */
+#define H1_HEADER_SIZE_OFFSET 0
+#define H1_HEADER_SUM_OFFSET 1
+#define H1_COMP_SIZE_OFFSET 7
+#define H1_ORIG_SIZE_OFFSET 11
+#define H1_DOS_TIME_OFFSET 15
+#define H1_NAME_LEN_OFFSET 21
+#define H1_FILE_NAME_OFFSET 22
+#define H1_FIXED_SIZE 27
+static int
+lha_read_file_header_1(struct archive_read *a, struct lha *lha)
+{
+ const unsigned char *p;
+ size_t extdsize;
+ int i, err, err2;
+ int namelen, padding;
+ unsigned char headersum, sum_calculated;
+
+ err = ARCHIVE_OK;
+
+ if ((p = __archive_read_ahead(a, H1_FIXED_SIZE, NULL)) == NULL)
+ return (truncated_error(a));
+
+ lha->header_size = p[H1_HEADER_SIZE_OFFSET] + 2;
+ headersum = p[H1_HEADER_SUM_OFFSET];
+ /* Note: An extended header size is included in a compsize. */
+ lha->compsize = archive_le32dec(p + H1_COMP_SIZE_OFFSET);
+ lha->origsize = archive_le32dec(p + H1_ORIG_SIZE_OFFSET);
+ lha->mtime = lha_dos_time(p + H1_DOS_TIME_OFFSET);
+ namelen = p[H1_NAME_LEN_OFFSET];
+ /* Calculate a padding size. The result will be normally 0 only(?) */
+ padding = ((int)lha->header_size) - H1_FIXED_SIZE - namelen;
+
+ if (namelen > 230 || padding < 0)
+ goto invalid;
+
+ if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL)
+ return (truncated_error(a));
+
+ for (i = 0; i < namelen; i++) {
+ if (p[i + H1_FILE_NAME_OFFSET] == 0xff)
+ goto invalid;/* Invalid filename. */
+ }
+ archive_strncpy(&lha->filename, p + H1_FILE_NAME_OFFSET, namelen);
+ lha->crc = archive_le16dec(p + H1_FILE_NAME_OFFSET + namelen);
+ lha->setflag |= CRC_IS_SET;
+
+ sum_calculated = lha_calcsum(0, p, 2, lha->header_size - 2);
+ /* Consume used bytes but not include `next header size' data
+ * since it will be consumed in lha_read_file_extended_header(). */
+ __archive_read_consume(a, lha->header_size - 2);
+
+ /* Read extended headers */
+ err2 = lha_read_file_extended_header(a, lha, NULL, 2,
+ lha->compsize + 2, &extdsize);
+ if (err2 < ARCHIVE_WARN)
+ return (err2);
+ if (err2 < err)
+ err = err2;
+ /* Get a real compressed file size. */
+ lha->compsize -= extdsize - 2;
+
+ if (sum_calculated != headersum) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "LHa header sum error");
+ return (ARCHIVE_FATAL);
+ }
+ return (err);
+invalid:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid LHa header");
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Header 2 format
+ *
+ * +0 +2 +7 +11 +15
+ * +---------------+----------------+-------------------+-----------------+
+ * |header size(*1)|compression type|compressed size(*2)|uncompressed size|
+ * +---------------+----------------+-------------------+-----------------+
+ * <--------------------------------(*1)---------------------------------*
+ *
+ * +15 +19 +20 +21 +23 +24
+ * +-----------------+------------+----------------+----------+-----------+
+ * |data/time(time_t)| 0x20 fixed |header level(=2)|file CRC16| creator |
+ * +-----------------+------------+----------------+----------+-----------+
+ * *---------------------------------(*1)---------------------------------*
+ *
+ * +24 +26 +26+(*3) +26+(*3)+(*4)
+ * +----------------+-------------------+-------------+-------------------+
+ * |next header size|extended header(*3)| padding(*4) | compressed data |
+ * +----------------+-------------------+-------------+-------------------+
+ * *--------------------------(*1)-------------------> <------(*2)------->
+ *
+ */
+#define H2_HEADER_SIZE_OFFSET 0
+#define H2_COMP_SIZE_OFFSET 7
+#define H2_ORIG_SIZE_OFFSET 11
+#define H2_TIME_OFFSET 15
+#define H2_CRC_OFFSET 21
+#define H2_FIXED_SIZE 24
+static int
+lha_read_file_header_2(struct archive_read *a, struct lha *lha)
+{
+ const unsigned char *p;
+ size_t extdsize;
+ int err, padding;
+ uint16_t header_crc;
+
+ if ((p = __archive_read_ahead(a, H2_FIXED_SIZE, NULL)) == NULL)
+ return (truncated_error(a));
+
+ lha->header_size =archive_le16dec(p + H2_HEADER_SIZE_OFFSET);
+ lha->compsize = archive_le32dec(p + H2_COMP_SIZE_OFFSET);
+ lha->origsize = archive_le32dec(p + H2_ORIG_SIZE_OFFSET);
+ lha->mtime = archive_le32dec(p + H2_TIME_OFFSET);
+ lha->crc = archive_le16dec(p + H2_CRC_OFFSET);
+ lha->setflag |= CRC_IS_SET;
+
+ if (lha->header_size < H2_FIXED_SIZE) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid LHa header size");
+ return (ARCHIVE_FATAL);
+ }
+
+ header_crc = lha_crc16(0, p, H2_FIXED_SIZE);
+ __archive_read_consume(a, H2_FIXED_SIZE);
+
+ /* Read extended headers */
+ err = lha_read_file_extended_header(a, lha, &header_crc, 2,
+ lha->header_size - H2_FIXED_SIZE, &extdsize);
+ if (err < ARCHIVE_WARN)
+ return (err);
+
+ /* Calculate a padding size. The result will be normally 0 or 1. */
+ padding = (int)lha->header_size - (int)(H2_FIXED_SIZE + extdsize);
+ if (padding > 0) {
+ if ((p = __archive_read_ahead(a, padding, NULL)) == NULL)
+ return (truncated_error(a));
+ header_crc = lha_crc16(header_crc, p, padding);
+ __archive_read_consume(a, padding);
+ }
+
+ if (header_crc != lha->header_crc) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "LHa header CRC error");
+ return (ARCHIVE_FATAL);
+ }
+ return (err);
+}
+
+/*
+ * Header 3 format
+ *
+ * +0 +2 +7 +11 +15
+ * +------------+----------------+-------------------+-----------------+
+ * | 0x04 fixed |compression type|compressed size(*2)|uncompressed size|
+ * +------------+----------------+-------------------+-----------------+
+ * <-------------------------------(*1)-------------------------------*
+ *
+ * +15 +19 +20 +21 +23 +24
+ * +-----------------+------------+----------------+----------+-----------+
+ * |date/time(time_t)| 0x20 fixed |header level(=3)|file CRC16| creator |
+ * +-----------------+------------+----------------+----------+-----------+
+ * *--------------------------------(*1)----------------------------------*
+ *
+ * +24 +28 +32 +32+(*3)
+ * +---------------+----------------+-------------------+-----------------+
+ * |header size(*1)|next header size|extended header(*3)| compressed data |
+ * +---------------+----------------+-------------------+-----------------+
+ * *------------------------(*1)-----------------------> <------(*2)----->
+ *
+ */
+#define H3_FIELD_LEN_OFFSET 0
+#define H3_COMP_SIZE_OFFSET 7
+#define H3_ORIG_SIZE_OFFSET 11
+#define H3_TIME_OFFSET 15
+#define H3_CRC_OFFSET 21
+#define H3_HEADER_SIZE_OFFSET 24
+#define H3_FIXED_SIZE 28
+static int
+lha_read_file_header_3(struct archive_read *a, struct lha *lha)
+{
+ const unsigned char *p;
+ size_t extdsize;
+ int err;
+ uint16_t header_crc;
+
+ if ((p = __archive_read_ahead(a, H3_FIXED_SIZE, NULL)) == NULL)
+ return (truncated_error(a));
+
+ if (archive_le16dec(p + H3_FIELD_LEN_OFFSET) != 4)
+ goto invalid;
+ lha->header_size =archive_le32dec(p + H3_HEADER_SIZE_OFFSET);
+ lha->compsize = archive_le32dec(p + H3_COMP_SIZE_OFFSET);
+ lha->origsize = archive_le32dec(p + H3_ORIG_SIZE_OFFSET);
+ lha->mtime = archive_le32dec(p + H3_TIME_OFFSET);
+ lha->crc = archive_le16dec(p + H3_CRC_OFFSET);
+ lha->setflag |= CRC_IS_SET;
+
+ if (lha->header_size < H3_FIXED_SIZE + 4)
+ goto invalid;
+ header_crc = lha_crc16(0, p, H3_FIXED_SIZE);
+ __archive_read_consume(a, H3_FIXED_SIZE);
+
+ /* Read extended headers */
+ err = lha_read_file_extended_header(a, lha, &header_crc, 4,
+ lha->header_size - H3_FIXED_SIZE, &extdsize);
+ if (err < ARCHIVE_WARN)
+ return (err);
+
+ if (header_crc != lha->header_crc) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "LHa header CRC error");
+ return (ARCHIVE_FATAL);
+ }
+ return (err);
+invalid:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid LHa header");
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Extended header format
+ *
+ * +0 +2 +3 -- used in header 1 and 2
+ * +0 +4 +5 -- used in header 3
+ * +--------------+---------+-------------------+--------------+--
+ * |ex-header size|header id| data |ex-header size| .......
+ * +--------------+---------+-------------------+--------------+--
+ * <-------------( ex-header size)------------> <-- next extended header --*
+ *
+ * If the ex-header size is zero, it is the make of the end of extended
+ * headers.
+ *
+ */
+static int
+lha_read_file_extended_header(struct archive_read *a, struct lha *lha,
+ uint16_t *crc, int sizefield_length, size_t limitsize, size_t *total_size)
+{
+ const void *h;
+ const unsigned char *extdheader;
+ size_t extdsize;
+ size_t datasize;
+ unsigned int i;
+ unsigned char extdtype;
+
+#define EXT_HEADER_CRC 0x00 /* Header CRC and information*/
+#define EXT_FILENAME 0x01 /* Filename */
+#define EXT_DIRECTORY 0x02 /* Directory name */
+#define EXT_DOS_ATTR 0x40 /* MS-DOS attribute */
+#define EXT_TIMESTAMP 0x41 /* Windows time stamp */
+#define EXT_FILESIZE 0x42 /* Large file size */
+#define EXT_TIMEZONE 0x43 /* Time zone */
+#define EXT_UTF16_FILENAME 0x44 /* UTF-16 filename */
+#define EXT_UTF16_DIRECTORY 0x45 /* UTF-16 directory name */
+#define EXT_CODEPAGE 0x46 /* Codepage */
+#define EXT_UNIX_MODE 0x50 /* File permission */
+#define EXT_UNIX_GID_UID 0x51 /* gid,uid */
+#define EXT_UNIX_GNAME 0x52 /* Group name */
+#define EXT_UNIX_UNAME 0x53 /* User name */
+#define EXT_UNIX_MTIME 0x54 /* Modified time */
+#define EXT_OS2_NEW_ATTR 0x7f /* new attribute(OS/2 only) */
+#define EXT_NEW_ATTR 0xff /* new attribute */
+
+ *total_size = sizefield_length;
+
+ for (;;) {
+ /* Read an extended header size. */
+ if ((h =
+ __archive_read_ahead(a, sizefield_length, NULL)) == NULL)
+ return (truncated_error(a));
+ /* Check if the size is the zero indicates the end of the
+ * extended header. */
+ if (sizefield_length == sizeof(uint16_t))
+ extdsize = archive_le16dec(h);
+ else
+ extdsize = archive_le32dec(h);
+ if (extdsize == 0) {
+ /* End of extended header */
+ if (crc != NULL)
+ *crc = lha_crc16(*crc, h, sizefield_length);
+ __archive_read_consume(a, sizefield_length);
+ return (ARCHIVE_OK);
+ }
+
+ /* Sanity check to the extended header size. */
+ if (((uint64_t)*total_size + extdsize) >
+ (uint64_t)limitsize ||
+ extdsize <= (size_t)sizefield_length)
+ goto invalid;
+
+ /* Read the extended header. */
+ if ((h = __archive_read_ahead(a, extdsize, NULL)) == NULL)
+ return (truncated_error(a));
+ *total_size += extdsize;
+
+ extdheader = (const unsigned char *)h;
+ /* Get the extended header type. */
+ extdtype = extdheader[sizefield_length];
+ /* Calculate an extended data size. */
+ datasize = extdsize - (1 + sizefield_length);
+ /* Skip an extended header size field and type field. */
+ extdheader += sizefield_length + 1;
+
+ if (crc != NULL && extdtype != EXT_HEADER_CRC)
+ *crc = lha_crc16(*crc, h, extdsize);
+ switch (extdtype) {
+ case EXT_HEADER_CRC:
+ /* We only use a header CRC. Following data will not
+ * be used. */
+ if (datasize >= 2) {
+ lha->header_crc = archive_le16dec(extdheader);
+ if (crc != NULL) {
+ static const char zeros[2] = {0, 0};
+ *crc = lha_crc16(*crc, h,
+ extdsize - datasize);
+ /* CRC value itself as zero */
+ *crc = lha_crc16(*crc, zeros, 2);
+ *crc = lha_crc16(*crc,
+ extdheader+2, datasize - 2);
+ }
+ }
+ break;
+ case EXT_FILENAME:
+ if (datasize == 0) {
+ /* maybe directory header */
+ archive_string_empty(&lha->filename);
+ break;
+ }
+ archive_strncpy(&lha->filename,
+ (const char *)extdheader, datasize);
+ break;
+ case EXT_DIRECTORY:
+ if (datasize == 0)
+ /* no directory name data. exit this case. */
+ break;
+
+ archive_strncpy(&lha->dirname,
+ (const char *)extdheader, datasize);
+ /*
+ * Convert directory delimiter from 0xFF
+ * to '/' for local system.
+ */
+ for (i = 0; i < lha->dirname.length; i++) {
+ if ((unsigned char)lha->dirname.s[i] == 0xFF)
+ lha->dirname.s[i] = '/';
+ }
+ /* Is last character directory separator? */
+ if (lha->dirname.s[lha->dirname.length-1] != '/')
+ /* invalid directory data */
+ goto invalid;
+ break;
+ case EXT_DOS_ATTR:
+ if (datasize == 2)
+ lha->dos_attr = (unsigned char)
+ (archive_le16dec(extdheader) & 0xff);
+ break;
+ case EXT_TIMESTAMP:
+ if (datasize == (sizeof(uint64_t) * 3)) {
+ lha->birthtime = lha_win_time(
+ archive_le64dec(extdheader),
+ &lha->birthtime_tv_nsec);
+ extdheader += sizeof(uint64_t);
+ lha->mtime = lha_win_time(
+ archive_le64dec(extdheader),
+ &lha->mtime_tv_nsec);
+ extdheader += sizeof(uint64_t);
+ lha->atime = lha_win_time(
+ archive_le64dec(extdheader),
+ &lha->atime_tv_nsec);
+ lha->setflag |= BIRTHTIME_IS_SET |
+ ATIME_IS_SET;
+ }
+ break;
+ case EXT_FILESIZE:
+ if (datasize == sizeof(uint64_t) * 2) {
+ lha->compsize = archive_le64dec(extdheader);
+ extdheader += sizeof(uint64_t);
+ lha->origsize = archive_le64dec(extdheader);
+ }
+ break;
+ case EXT_CODEPAGE:
+ /* Get an archived filename charset from codepage.
+ * This overwrites the charset specified by
+ * hdrcharset option. */
+ if (datasize == sizeof(uint32_t)) {
+ struct archive_string cp;
+ const char *charset;
+
+ archive_string_init(&cp);
+ switch (archive_le32dec(extdheader)) {
+ case 65001: /* UTF-8 */
+ charset = "UTF-8";
+ break;
+ default:
+ archive_string_sprintf(&cp, "CP%d",
+ (int)archive_le32dec(extdheader));
+ charset = cp.s;
+ break;
+ }
+ lha->sconv =
+ archive_string_conversion_from_charset(
+ &(a->archive), charset, 1);
+ archive_string_free(&cp);
+ if (lha->sconv == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ break;
+ case EXT_UNIX_MODE:
+ if (datasize == sizeof(uint16_t)) {
+ lha->mode = archive_le16dec(extdheader);
+ lha->setflag |= UNIX_MODE_IS_SET;
+ }
+ break;
+ case EXT_UNIX_GID_UID:
+ if (datasize == (sizeof(uint16_t) * 2)) {
+ lha->gid = archive_le16dec(extdheader);
+ lha->uid = archive_le16dec(extdheader+2);
+ }
+ break;
+ case EXT_UNIX_GNAME:
+ if (datasize > 0)
+ archive_strncpy(&lha->gname,
+ (const char *)extdheader, datasize);
+ break;
+ case EXT_UNIX_UNAME:
+ if (datasize > 0)
+ archive_strncpy(&lha->uname,
+ (const char *)extdheader, datasize);
+ break;
+ case EXT_UNIX_MTIME:
+ if (datasize == sizeof(uint32_t))
+ lha->mtime = archive_le32dec(extdheader);
+ break;
+ case EXT_OS2_NEW_ATTR:
+ /* This extended header is OS/2 depend. */
+ if (datasize == 16) {
+ lha->dos_attr = (unsigned char)
+ (archive_le16dec(extdheader) & 0xff);
+ lha->mode = archive_le16dec(extdheader+2);
+ lha->gid = archive_le16dec(extdheader+4);
+ lha->uid = archive_le16dec(extdheader+6);
+ lha->birthtime = archive_le32dec(extdheader+8);
+ lha->atime = archive_le32dec(extdheader+12);
+ lha->setflag |= UNIX_MODE_IS_SET
+ | BIRTHTIME_IS_SET | ATIME_IS_SET;
+ }
+ break;
+ case EXT_NEW_ATTR:
+ if (datasize == 20) {
+ lha->mode = (mode_t)archive_le32dec(extdheader);
+ lha->gid = archive_le32dec(extdheader+4);
+ lha->uid = archive_le32dec(extdheader+8);
+ lha->birthtime = archive_le32dec(extdheader+12);
+ lha->atime = archive_le32dec(extdheader+16);
+ lha->setflag |= UNIX_MODE_IS_SET
+ | BIRTHTIME_IS_SET | ATIME_IS_SET;
+ }
+ break;
+ case EXT_TIMEZONE: /* Not supported */
+ case EXT_UTF16_FILENAME: /* Not supported */
+ case EXT_UTF16_DIRECTORY: /* Not supported */
+ default:
+ break;
+ }
+
+ __archive_read_consume(a, extdsize);
+ }
+invalid:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid extended LHa header");
+ return (ARCHIVE_FATAL);
+}
+
+static int
+archive_read_format_lha_read_data(struct archive_read *a,
+ const void **buff, size_t *size, int64_t *offset)
+{
+ struct lha *lha = (struct lha *)(a->format->data);
+ int r;
+
+ if (lha->entry_unconsumed) {
+ /* Consume as much as the decompressor actually used. */
+ __archive_read_consume(a, lha->entry_unconsumed);
+ lha->entry_unconsumed = 0;
+ }
+ if (lha->end_of_entry) {
+ if (!lha->end_of_entry_cleanup) {
+ if ((lha->setflag & CRC_IS_SET) &&
+ lha->crc != lha->entry_crc_calculated) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "LHa data CRC error");
+ return (ARCHIVE_WARN);
+ }
+
+ /* End-of-entry cleanup done. */
+ lha->end_of_entry_cleanup = 1;
+ }
+ *offset = lha->entry_offset;
+ *size = 0;
+ *buff = NULL;
+ return (ARCHIVE_EOF);
+ }
+
+ if (lha->entry_is_compressed)
+ r = lha_read_data_lzh(a, buff, size, offset);
+ else
+ /* No compression. */
+ r = lha_read_data_none(a, buff, size, offset);
+ return (r);
+}
+
+/*
+ * Read a file content in no compression.
+ *
+ * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
+ * lha->end_of_entry if it consumes all of the data.
+ */
+static int
+lha_read_data_none(struct archive_read *a, const void **buff,
+ size_t *size, int64_t *offset)
+{
+ struct lha *lha = (struct lha *)(a->format->data);
+ ssize_t bytes_avail;
+
+ if (lha->entry_bytes_remaining == 0) {
+ *buff = NULL;
+ *size = 0;
+ *offset = lha->entry_offset;
+ lha->end_of_entry = 1;
+ return (ARCHIVE_OK);
+ }
+ /*
+ * Note: '1' here is a performance optimization.
+ * Recall that the decompression layer returns a count of
+ * available bytes; asking for more than that forces the
+ * decompressor to combine reads by copying data.
+ */
+ *buff = __archive_read_ahead(a, 1, &bytes_avail);
+ if (bytes_avail <= 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated LHa file data");
+ return (ARCHIVE_FATAL);
+ }
+ if (bytes_avail > lha->entry_bytes_remaining)
+ bytes_avail = lha->entry_bytes_remaining;
+ lha->entry_crc_calculated =
+ lha_crc16(lha->entry_crc_calculated, *buff, bytes_avail);
+ *size = bytes_avail;
+ *offset = lha->entry_offset;
+ lha->entry_offset += bytes_avail;
+ lha->entry_bytes_remaining -= bytes_avail;
+ if (lha->entry_bytes_remaining == 0)
+ lha->end_of_entry = 1;
+ lha->entry_unconsumed = bytes_avail;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Read a file content in LZHUFF encoding.
+ *
+ * Returns ARCHIVE_OK if successful, returns ARCHIVE_WARN if compression is
+ * unsupported, ARCHIVE_FATAL otherwise, sets lha->end_of_entry if it consumes
+ * all of the data.
+ */
+static int
+lha_read_data_lzh(struct archive_read *a, const void **buff,
+ size_t *size, int64_t *offset)
+{
+ struct lha *lha = (struct lha *)(a->format->data);
+ ssize_t bytes_avail;
+ int r;
+
+ /* If the buffer hasn't been allocated, allocate it now. */
+ if (lha->uncompressed_buffer == NULL) {
+ lha->uncompressed_buffer_size = 64 * 1024;
+ lha->uncompressed_buffer
+ = (unsigned char *)malloc(lha->uncompressed_buffer_size);
+ if (lha->uncompressed_buffer == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory for lzh decompression");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ /* If we haven't yet read any data, initialize the decompressor. */
+ if (!lha->decompress_init) {
+ r = lzh_decode_init(&(lha->strm), lha->method);
+ switch (r) {
+ case ARCHIVE_OK:
+ break;
+ case ARCHIVE_FAILED:
+ /* Unsupported compression. */
+ *buff = NULL;
+ *size = 0;
+ *offset = 0;
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unsupported lzh compression method -%c%c%c-",
+ lha->method[0], lha->method[1], lha->method[2]);
+ /* We know compressed size; just skip it. */
+ archive_read_format_lha_read_data_skip(a);
+ return (ARCHIVE_WARN);
+ default:
+ archive_set_error(&a->archive, ENOMEM,
+ "Couldn't allocate memory "
+ "for lzh decompression");
+ return (ARCHIVE_FATAL);
+ }
+ /* We've initialized decompression for this stream. */
+ lha->decompress_init = 1;
+ lha->strm.avail_out = 0;
+ lha->strm.total_out = 0;
+ }
+
+ /*
+ * Note: '1' here is a performance optimization.
+ * Recall that the decompression layer returns a count of
+ * available bytes; asking for more than that forces the
+ * decompressor to combine reads by copying data.
+ */
+ lha->strm.next_in = __archive_read_ahead(a, 1, &bytes_avail);
+ if (bytes_avail <= 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated LHa file body");
+ return (ARCHIVE_FATAL);
+ }
+ if (bytes_avail > lha->entry_bytes_remaining)
+ bytes_avail = lha->entry_bytes_remaining;
+
+ lha->strm.avail_in = bytes_avail;
+ lha->strm.total_in = 0;
+ if (lha->strm.avail_out == 0) {
+ lha->strm.next_out = lha->uncompressed_buffer;
+ lha->strm.avail_out = lha->uncompressed_buffer_size;
+ }
+
+ r = lzh_decode(&(lha->strm), bytes_avail == lha->entry_bytes_remaining);
+ switch (r) {
+ case ARCHIVE_OK:
+ break;
+ case ARCHIVE_EOF:
+ lha->end_of_entry = 1;
+ break;
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Bad lzh data");
+ return (ARCHIVE_FAILED);
+ }
+ lha->entry_unconsumed = lha->strm.total_in;
+ lha->entry_bytes_remaining -= lha->strm.total_in;
+
+ if (lha->strm.avail_out == 0 || lha->end_of_entry) {
+ *offset = lha->entry_offset;
+ *size = lha->strm.next_out - lha->uncompressed_buffer;
+ *buff = lha->uncompressed_buffer;
+ lha->entry_crc_calculated =
+ lha_crc16(lha->entry_crc_calculated, *buff, *size);
+ lha->entry_offset += *size;
+ } else {
+ *offset = lha->entry_offset;
+ *size = 0;
+ *buff = NULL;
+ }
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Skip a file content.
+ */
+static int
+archive_read_format_lha_read_data_skip(struct archive_read *a)
+{
+ struct lha *lha;
+ off_t bytes_skipped;
+
+ lha = (struct lha *)(a->format->data);
+
+ if (lha->entry_unconsumed) {
+ /* Consume as much as the decompressor actually used. */
+ __archive_read_consume(a, lha->entry_unconsumed);
+ lha->entry_unconsumed = 0;
+ }
+
+ /* if we've already read to end of data, we're done. */
+ if (lha->end_of_entry_cleanup)
+ return (ARCHIVE_OK);
+
+ /*
+ * If the length is at the beginning, we can skip the
+ * compressed data much more quickly.
+ */
+ bytes_skipped = __archive_read_consume(a, lha->entry_bytes_remaining);
+ if (bytes_skipped < 0)
+ return (ARCHIVE_FATAL);
+
+ /* This entry is finished and done. */
+ lha->end_of_entry_cleanup = lha->end_of_entry = 1;
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_lha_cleanup(struct archive_read *a)
+{
+ struct lha *lha = (struct lha *)(a->format->data);
+
+ lzh_decode_free(&(lha->strm));
+ free(lha->uncompressed_buffer);
+ archive_string_free(&(lha->dirname));
+ archive_string_free(&(lha->filename));
+ archive_string_free(&(lha->uname));
+ archive_string_free(&(lha->gname));
+ archive_wstring_free(&(lha->ws));
+ free(lha);
+ (a->format->data) = NULL;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * 'LHa for UNIX' utility has archived a symbolic-link name after
+ * a pathname with '|' character.
+ * This function extracts the symbolic-link name from the pathname.
+ *
+ * example.
+ * 1. a symbolic-name is 'aaa/bb/cc'
+ * 2. a filename is 'xxx/bbb'
+ * then a archived pathname is 'xxx/bbb|aaa/bb/cc'
+ */
+static int
+lha_parse_linkname(struct archive_string *linkname,
+ struct archive_string *pathname)
+{
+ char * linkptr;
+ int symlen;
+
+ linkptr = strchr(pathname->s, '|');
+ if (linkptr != NULL) {
+ symlen = strlen(linkptr + 1);
+ archive_strncpy(linkname, linkptr+1, symlen);
+
+ *linkptr = 0;
+ pathname->length = strlen(pathname->s);
+
+ return (1);
+ }
+ return (0);
+}
+
+/* Convert an MSDOS-style date/time into Unix-style time. */
+static time_t
+lha_dos_time(const unsigned char *p)
+{
+ int msTime, msDate;
+ struct tm ts;
+
+ msTime = archive_le16dec(p);
+ msDate = archive_le16dec(p+2);
+
+ memset(&ts, 0, sizeof(ts));
+ ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
+ ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
+ ts.tm_mday = msDate & 0x1f; /* Day of month. */
+ ts.tm_hour = (msTime >> 11) & 0x1f;
+ ts.tm_min = (msTime >> 5) & 0x3f;
+ ts.tm_sec = (msTime << 1) & 0x3e;
+ ts.tm_isdst = -1;
+ return (mktime(&ts));
+}
+
+/* Convert an MS-Windows-style date/time into Unix-style time. */
+static time_t
+lha_win_time(uint64_t wintime, long *ns)
+{
+#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
+
+ if (wintime >= EPOC_TIME) {
+ wintime -= EPOC_TIME; /* 1970-01-01 00:00:00 (UTC) */
+ if (ns != NULL)
+ *ns = (long)(wintime % 10000000) * 100;
+ return (wintime / 10000000);
+ } else {
+ if (ns != NULL)
+ *ns = 0;
+ return (0);
+ }
+}
+
+static unsigned char
+lha_calcsum(unsigned char sum, const void *pp, int offset, int size)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ p += offset;
+ while (--size >= 0)
+ sum += *p++;
+ return (sum);
+}
+
+#define CRC16(crc, v) do { \
+ (crc) = crc16tbl[((crc) ^ v) & 0xFF] ^ ((crc) >> 8); \
+} while (0)
+
+static uint16_t
+lha_crc16(uint16_t crc, const void *pp, size_t len)
+{
+ const unsigned char *buff = (const unsigned char *)pp;
+
+ while (len >= 8) {
+ CRC16(crc, *buff++); CRC16(crc, *buff++);
+ CRC16(crc, *buff++); CRC16(crc, *buff++);
+ CRC16(crc, *buff++); CRC16(crc, *buff++);
+ CRC16(crc, *buff++); CRC16(crc, *buff++);
+ len -= 8;
+ }
+ switch (len) {
+ case 7:
+ CRC16(crc, *buff++);
+ /* FALL THROUGH */
+ case 6:
+ CRC16(crc, *buff++);
+ /* FALL THROUGH */
+ case 5:
+ CRC16(crc, *buff++);
+ /* FALL THROUGH */
+ case 4:
+ CRC16(crc, *buff++);
+ /* FALL THROUGH */
+ case 3:
+ CRC16(crc, *buff++);
+ /* FALL THROUGH */
+ case 2:
+ CRC16(crc, *buff++);
+ /* FALL THROUGH */
+ case 1:
+ CRC16(crc, *buff);
+ /* FALL THROUGH */
+ case 0:
+ break;
+ }
+ return (crc);
+}
+
+
+/*
+ * Initialize LZHUF decoder.
+ *
+ * Returns ARCHIVE_OK if initialization was successful.
+ * Returns ARCHIVE_FAILED if method is unsupported.
+ * Returns ARCHIVE_FATAL if initialization failed; memory allocation
+ * error occurred.
+ */
+static int
+lzh_decode_init(struct lzh_stream *strm, const char *method)
+{
+ struct lzh_dec *ds;
+ int w_bits, w_size;
+
+ if (strm->ds == NULL) {
+ strm->ds = calloc(1, sizeof(*strm->ds));
+ if (strm->ds == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ ds = strm->ds;
+ ds->error = ARCHIVE_FAILED;
+ if (method == NULL || method[0] != 'l' || method[1] != 'h')
+ return (ARCHIVE_FAILED);
+ switch (method[2]) {
+ case '5':
+ w_bits = 13;/* 8KiB for window */
+ break;
+ case '6':
+ w_bits = 15;/* 32KiB for window */
+ break;
+ case '7':
+ w_bits = 16;/* 64KiB for window */
+ break;
+ default:
+ return (ARCHIVE_FAILED);/* Not supported. */
+ }
+ ds->error = ARCHIVE_FATAL;
+ w_size = ds->w_size;
+ ds->w_size = 1U << w_bits;
+ ds->w_mask = ds->w_size -1;
+ if (ds->w_buff == NULL || w_size != ds->w_size) {
+ free(ds->w_buff);
+ ds->w_buff = malloc(ds->w_size);
+ if (ds->w_buff == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ memset(ds->w_buff, 0x20, ds->w_size);
+ ds->w_pos = 0;
+ ds->w_remaining = 0;
+ ds->state = 0;
+ ds->pos_pt_len_size = w_bits + 1;
+ ds->pos_pt_len_bits = (w_bits == 15 || w_bits == 16)? 5: 4;
+ ds->literal_pt_len_size = PT_BITLEN_SIZE;
+ ds->literal_pt_len_bits = 5;
+ ds->br.cache_buffer = 0;
+ ds->br.cache_avail = 0;
+
+ if (lzh_huffman_init(&(ds->lt), LT_BITLEN_SIZE, 16)
+ != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ ds->lt.len_bits = 9;
+ if (lzh_huffman_init(&(ds->pt), PT_BITLEN_SIZE, 16)
+ != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ ds->error = 0;
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Release LZHUF decoder.
+ */
+static void
+lzh_decode_free(struct lzh_stream *strm)
+{
+
+ if (strm->ds == NULL)
+ return;
+ free(strm->ds->w_buff);
+ lzh_huffman_free(&(strm->ds->lt));
+ lzh_huffman_free(&(strm->ds->pt));
+ free(strm->ds);
+ strm->ds = NULL;
+}
+
+/*
+ * Bit stream reader.
+ */
+/* Check that the cache buffer has enough bits. */
+#define lzh_br_has(br, n) ((br)->cache_avail >= n)
+/* Get compressed data by bit. */
+#define lzh_br_bits(br, n) \
+ (((uint16_t)((br)->cache_buffer >> \
+ ((br)->cache_avail - (n)))) & cache_masks[n])
+#define lzh_br_bits_forced(br, n) \
+ (((uint16_t)((br)->cache_buffer << \
+ ((n) - (br)->cache_avail))) & cache_masks[n])
+/* Read ahead to make sure the cache buffer has enough compressed data we
+ * will use.
+ * True : completed, there is enough data in the cache buffer.
+ * False : we met that strm->next_in is empty, we have to get following
+ * bytes. */
+#define lzh_br_read_ahead_0(strm, br, n) \
+ (lzh_br_has(br, (n)) || lzh_br_fillup(strm, br))
+/* True : the cache buffer has some bits as much as we need.
+ * False : there are no enough bits in the cache buffer to be used,
+ * we have to get following bytes if we could. */
+#define lzh_br_read_ahead(strm, br, n) \
+ (lzh_br_read_ahead_0((strm), (br), (n)) || lzh_br_has((br), (n)))
+
+/* Notify how many bits we consumed. */
+#define lzh_br_consume(br, n) ((br)->cache_avail -= (n))
+#define lzh_br_unconsume(br, n) ((br)->cache_avail += (n))
+
+static const uint16_t cache_masks[] = {
+ 0x0000, 0x0001, 0x0003, 0x0007,
+ 0x000F, 0x001F, 0x003F, 0x007F,
+ 0x00FF, 0x01FF, 0x03FF, 0x07FF,
+ 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF,
+ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
+};
+
+/*
+ * Shift away used bits in the cache data and fill it up with following bits.
+ * Call this when cache buffer does not have enough bits you need.
+ *
+ * Returns 1 if the cache buffer is full.
+ * Returns 0 if the cache buffer is not full; input buffer is empty.
+ */
+static int
+lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br)
+{
+ int n = CACHE_BITS - br->cache_avail;
+
+ for (;;) {
+ switch (n >> 3) {
+ case 8:
+ if (strm->avail_in >= 8) {
+ br->cache_buffer =
+ ((uint64_t)strm->next_in[0]) << 56 |
+ ((uint64_t)strm->next_in[1]) << 48 |
+ ((uint64_t)strm->next_in[2]) << 40 |
+ ((uint64_t)strm->next_in[3]) << 32 |
+ ((uint32_t)strm->next_in[4]) << 24 |
+ ((uint32_t)strm->next_in[5]) << 16 |
+ ((uint32_t)strm->next_in[6]) << 8 |
+ (uint32_t)strm->next_in[7];
+ strm->next_in += 8;
+ strm->avail_in -= 8;
+ br->cache_avail += 8 * 8;
+ return (1);
+ }
+ break;
+ case 7:
+ if (strm->avail_in >= 7) {
+ br->cache_buffer =
+ (br->cache_buffer << 56) |
+ ((uint64_t)strm->next_in[0]) << 48 |
+ ((uint64_t)strm->next_in[1]) << 40 |
+ ((uint64_t)strm->next_in[2]) << 32 |
+ ((uint32_t)strm->next_in[3]) << 24 |
+ ((uint32_t)strm->next_in[4]) << 16 |
+ ((uint32_t)strm->next_in[5]) << 8 |
+ (uint32_t)strm->next_in[6];
+ strm->next_in += 7;
+ strm->avail_in -= 7;
+ br->cache_avail += 7 * 8;
+ return (1);
+ }
+ break;
+ case 6:
+ if (strm->avail_in >= 6) {
+ br->cache_buffer =
+ (br->cache_buffer << 48) |
+ ((uint64_t)strm->next_in[0]) << 40 |
+ ((uint64_t)strm->next_in[1]) << 32 |
+ ((uint32_t)strm->next_in[2]) << 24 |
+ ((uint32_t)strm->next_in[3]) << 16 |
+ ((uint32_t)strm->next_in[4]) << 8 |
+ (uint32_t)strm->next_in[5];
+ strm->next_in += 6;
+ strm->avail_in -= 6;
+ br->cache_avail += 6 * 8;
+ return (1);
+ }
+ break;
+ case 0:
+ /* We have enough compressed data in
+ * the cache buffer.*/
+ return (1);
+ default:
+ break;
+ }
+ if (strm->avail_in == 0) {
+ /* There is not enough compressed data to fill up the
+ * cache buffer. */
+ return (0);
+ }
+ br->cache_buffer =
+ (br->cache_buffer << 8) | *strm->next_in++;
+ strm->avail_in--;
+ br->cache_avail += 8;
+ n -= 8;
+ }
+}
+
+/*
+ * Decode LZHUF.
+ *
+ * 1. Returns ARCHIVE_OK if output buffer or input buffer are empty.
+ * Please set available buffer and call this function again.
+ * 2. Returns ARCHIVE_EOF if decompression has been completed.
+ * 3. Returns ARCHIVE_FAILED if an error occurred; compressed data
+ * is broken or you do not set 'last' flag properly.
+ * 4. 'last' flag is very important, you must set 1 to the flag if there
+ * is no input data. The lha compressed data format does not provide how
+ * to know the compressed data is really finished.
+ * Note: lha command utility check if the total size of output bytes is
+ * reached the uncompressed size recorded in its header. it does not mind
+ * that the decoding process is properly finished.
+ * GNU ZIP can decompress another compressed file made by SCO LZH compress.
+ * it handles EOF as null to fill read buffer with zero until the decoding
+ * process meet 2 bytes of zeros at reading a size of a next chunk, so the
+ * zeros are treated as the mark of the end of the data although the zeros
+ * is dummy, not the file data.
+ */
+static int lzh_read_blocks(struct lzh_stream *, int);
+static int lzh_decode_blocks(struct lzh_stream *, int);
+#define ST_RD_BLOCK 0
+#define ST_RD_PT_1 1
+#define ST_RD_PT_2 2
+#define ST_RD_PT_3 3
+#define ST_RD_PT_4 4
+#define ST_RD_LITERAL_1 5
+#define ST_RD_LITERAL_2 6
+#define ST_RD_LITERAL_3 7
+#define ST_RD_POS_DATA_1 8
+#define ST_GET_LITERAL 9
+#define ST_GET_POS_1 10
+#define ST_GET_POS_2 11
+#define ST_COPY_DATA 12
+
+static int
+lzh_decode(struct lzh_stream *strm, int last)
+{
+ struct lzh_dec *ds = strm->ds;
+ int64_t avail_in;
+ int r;
+
+ if (ds->error)
+ return (ds->error);
+
+ avail_in = strm->avail_in;
+ do {
+ if (ds->state < ST_GET_LITERAL)
+ r = lzh_read_blocks(strm, last);
+ else
+ r = lzh_decode_blocks(strm, last);
+ } while (r == 100);
+ strm->total_in += avail_in - strm->avail_in;
+ return (r);
+}
+
+static int
+lzh_copy_from_window(struct lzh_stream *strm, struct lzh_dec *ds)
+{
+ size_t copy_bytes;
+
+ if (ds->w_remaining == 0 && ds->w_pos > 0) {
+ if (ds->w_pos - ds->copy_pos <= strm->avail_out)
+ copy_bytes = ds->w_pos - ds->copy_pos;
+ else
+ copy_bytes = strm->avail_out;
+ memcpy(strm->next_out,
+ ds->w_buff + ds->copy_pos, copy_bytes);
+ ds->copy_pos += copy_bytes;
+ } else {
+ if (ds->w_remaining <= strm->avail_out)
+ copy_bytes = ds->w_remaining;
+ else
+ copy_bytes = strm->avail_out;
+ memcpy(strm->next_out,
+ ds->w_buff + ds->w_size - ds->w_remaining, copy_bytes);
+ ds->w_remaining -= copy_bytes;
+ }
+ strm->next_out += copy_bytes;
+ strm->avail_out -= copy_bytes;
+ strm->total_out += copy_bytes;
+ if (strm->avail_out == 0)
+ return (0);
+ else
+ return (1);
+}
+
+static int
+lzh_read_blocks(struct lzh_stream *strm, int last)
+{
+ struct lzh_dec *ds = strm->ds;
+ struct lzh_br *br = &(ds->br);
+ int c = 0, i;
+ unsigned rbits;
+
+ for (;;) {
+ switch (ds->state) {
+ case ST_RD_BLOCK:
+ /*
+ * Read a block number indicates how many blocks
+ * we will handle. The block is composed of a
+ * literal and a match, sometimes a literal only
+ * in particular, there are no reference data at
+ * the beginning of the decompression.
+ */
+ if (!lzh_br_read_ahead_0(strm, br, 16)) {
+ if (!last)
+ /* We need following data. */
+ return (ARCHIVE_OK);
+ if (lzh_br_has(br, 8)) {
+ /*
+ * It seems there are extra bits.
+ * 1. Compressed data is broken.
+ * 2. `last' flag does not properly
+ * set.
+ */
+ goto failed;
+ }
+ if (ds->w_pos > 0) {
+ if (!lzh_copy_from_window(strm, ds))
+ return (ARCHIVE_OK);
+ }
+ /* End of compressed data; we have completely
+ * handled all compressed data. */
+ return (ARCHIVE_EOF);
+ }
+ ds->blocks_avail = lzh_br_bits(br, 16);
+ if (ds->blocks_avail == 0)
+ goto failed;
+ lzh_br_consume(br, 16);
+ /*
+ * Read a literal table compressed in huffman
+ * coding.
+ */
+ ds->pt.len_size = ds->literal_pt_len_size;
+ ds->pt.len_bits = ds->literal_pt_len_bits;
+ ds->reading_position = 0;
+ /* FALL THROUGH */
+ case ST_RD_PT_1:
+ /* Note: ST_RD_PT_1, ST_RD_PT_2 and ST_RD_PT_4 are
+ * used in reading both a literal table and a
+ * position table. */
+ if (!lzh_br_read_ahead(strm, br, ds->pt.len_bits)) {
+ if (last)
+ goto failed;/* Truncated data. */
+ ds->state = ST_RD_PT_1;
+ return (ARCHIVE_OK);
+ }
+ ds->pt.len_avail = lzh_br_bits(br, ds->pt.len_bits);
+ lzh_br_consume(br, ds->pt.len_bits);
+ /* FALL THROUGH */
+ case ST_RD_PT_2:
+ if (ds->pt.len_avail == 0) {
+ /* There is no bitlen. */
+ if (!lzh_br_read_ahead(strm, br,
+ ds->pt.len_bits)) {
+ if (last)
+ goto failed;/* Truncated data.*/
+ ds->state = ST_RD_PT_2;
+ return (ARCHIVE_OK);
+ }
+ if (!lzh_make_fake_table(&(ds->pt),
+ lzh_br_bits(br, ds->pt.len_bits)))
+ goto failed;/* Invalid data. */
+ lzh_br_consume(br, ds->pt.len_bits);
+ if (ds->reading_position)
+ ds->state = ST_GET_LITERAL;
+ else
+ ds->state = ST_RD_LITERAL_1;
+ break;
+ } else if (ds->pt.len_avail > ds->pt.len_size)
+ goto failed;/* Invalid data. */
+ ds->loop = 0;
+ memset(ds->pt.freq, 0, sizeof(ds->pt.freq));
+ if (ds->pt.len_avail < 3 ||
+ ds->pt.len_size == ds->pos_pt_len_size) {
+ ds->state = ST_RD_PT_4;
+ break;
+ }
+ /* FALL THROUGH */
+ case ST_RD_PT_3:
+ ds->loop = lzh_read_pt_bitlen(strm, ds->loop, 3);
+ if (ds->loop < 3) {
+ if (ds->loop < 0 || last)
+ goto failed;/* Invalid data. */
+ /* Not completed, get following data. */
+ ds->state = ST_RD_PT_3;
+ return (ARCHIVE_OK);
+ }
+ /* There are some null in bitlen of the literal. */
+ if (!lzh_br_read_ahead(strm, br, 2)) {
+ if (last)
+ goto failed;/* Truncated data. */
+ ds->state = ST_RD_PT_3;
+ return (ARCHIVE_OK);
+ }
+ c = lzh_br_bits(br, 2);
+ lzh_br_consume(br, 2);
+ if (c > ds->pt.len_avail - 3)
+ goto failed;/* Invalid data. */
+ for (i = 3; c-- > 0 ;)
+ ds->pt.bitlen[i++] = 0;
+ ds->loop = i;
+ /* FALL THROUGH */
+ case ST_RD_PT_4:
+ ds->loop = lzh_read_pt_bitlen(strm, ds->loop,
+ ds->pt.len_avail);
+ if (ds->loop < ds->pt.len_avail) {
+ if (ds->loop < 0 || last)
+ goto failed;/* Invalid data. */
+ /* Not completed, get following data. */
+ ds->state = ST_RD_PT_4;
+ return (ARCHIVE_OK);
+ }
+ if (!lzh_make_huffman_table(&(ds->pt)))
+ goto failed;/* Invalid data */
+ if (ds->reading_position) {
+ ds->state = ST_GET_LITERAL;
+ break;
+ }
+ /* FALL THROUGH */
+ case ST_RD_LITERAL_1:
+ if (!lzh_br_read_ahead(strm, br, ds->lt.len_bits)) {
+ if (last)
+ goto failed;/* Truncated data. */
+ ds->state = ST_RD_LITERAL_1;
+ return (ARCHIVE_OK);
+ }
+ ds->lt.len_avail = lzh_br_bits(br, ds->lt.len_bits);
+ lzh_br_consume(br, ds->lt.len_bits);
+ /* FALL THROUGH */
+ case ST_RD_LITERAL_2:
+ if (ds->lt.len_avail == 0) {
+ /* There is no bitlen. */
+ if (!lzh_br_read_ahead(strm, br,
+ ds->lt.len_bits)) {
+ if (last)
+ goto failed;/* Truncated data.*/
+ ds->state = ST_RD_LITERAL_2;
+ return (ARCHIVE_OK);
+ }
+ if (!lzh_make_fake_table(&(ds->lt),
+ lzh_br_bits(br, ds->lt.len_bits)))
+ goto failed;/* Invalid data */
+ lzh_br_consume(br, ds->lt.len_bits);
+ ds->state = ST_RD_POS_DATA_1;
+ break;
+ } else if (ds->lt.len_avail > ds->lt.len_size)
+ goto failed;/* Invalid data */
+ ds->loop = 0;
+ memset(ds->lt.freq, 0, sizeof(ds->lt.freq));
+ /* FALL THROUGH */
+ case ST_RD_LITERAL_3:
+ i = ds->loop;
+ while (i < ds->lt.len_avail) {
+ if (!lzh_br_read_ahead(strm, br,
+ ds->pt.max_bits)) {
+ if (last)
+ goto failed;/* Truncated data.*/
+ ds->loop = i;
+ ds->state = ST_RD_LITERAL_3;
+ return (ARCHIVE_OK);
+ }
+ rbits = lzh_br_bits(br, ds->pt.max_bits);
+ c = lzh_decode_huffman(&(ds->pt), rbits);
+ if (c > 2) {
+ /* Note: 'c' will never be more than
+ * eighteen since it's limited by
+ * PT_BITLEN_SIZE, which is being set
+ * to ds->pt.len_size through
+ * ds->literal_pt_len_size. */
+ lzh_br_consume(br, ds->pt.bitlen[c]);
+ c -= 2;
+ ds->lt.freq[c]++;
+ ds->lt.bitlen[i++] = c;
+ } else if (c == 0) {
+ lzh_br_consume(br, ds->pt.bitlen[c]);
+ ds->lt.bitlen[i++] = 0;
+ } else {
+ /* c == 1 or c == 2 */
+ int n = (c == 1)?4:9;
+ if (!lzh_br_read_ahead(strm, br,
+ ds->pt.bitlen[c] + n)) {
+ if (last) /* Truncated data. */
+ goto failed;
+ ds->loop = i;
+ ds->state = ST_RD_LITERAL_3;
+ return (ARCHIVE_OK);
+ }
+ lzh_br_consume(br, ds->pt.bitlen[c]);
+ c = lzh_br_bits(br, n);
+ lzh_br_consume(br, n);
+ c += (n == 4)?3:20;
+ if (i + c > ds->lt.len_avail)
+ goto failed;/* Invalid data */
+ memset(&(ds->lt.bitlen[i]), 0, c);
+ i += c;
+ }
+ }
+ if (i > ds->lt.len_avail ||
+ !lzh_make_huffman_table(&(ds->lt)))
+ goto failed;/* Invalid data */
+ /* FALL THROUGH */
+ case ST_RD_POS_DATA_1:
+ /*
+ * Read a position table compressed in huffman
+ * coding.
+ */
+ ds->pt.len_size = ds->pos_pt_len_size;
+ ds->pt.len_bits = ds->pos_pt_len_bits;
+ ds->reading_position = 1;
+ ds->state = ST_RD_PT_1;
+ break;
+ case ST_GET_LITERAL:
+ return (100);
+ }
+ }
+failed:
+ return (ds->error = ARCHIVE_FAILED);
+}
+
+static int
+lzh_decode_blocks(struct lzh_stream *strm, int last)
+{
+ struct lzh_dec *ds = strm->ds;
+ struct lzh_br bre = ds->br;
+ struct huffman *lt = &(ds->lt);
+ struct huffman *pt = &(ds->pt);
+ unsigned char *w_buff = ds->w_buff;
+ unsigned char *lt_bitlen = lt->bitlen;
+ unsigned char *pt_bitlen = pt->bitlen;
+ int blocks_avail = ds->blocks_avail, c = 0;
+ int copy_len = ds->copy_len, copy_pos = ds->copy_pos;
+ int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
+ int lt_max_bits = lt->max_bits, pt_max_bits = pt->max_bits;
+ int state = ds->state;
+
+ if (ds->w_remaining > 0) {
+ if (!lzh_copy_from_window(strm, ds))
+ goto next_data;
+ }
+ for (;;) {
+ switch (state) {
+ case ST_GET_LITERAL:
+ for (;;) {
+ if (blocks_avail == 0) {
+ /* We have decoded all blocks.
+ * Let's handle next blocks. */
+ ds->state = ST_RD_BLOCK;
+ ds->br = bre;
+ ds->blocks_avail = 0;
+ ds->w_pos = w_pos;
+ ds->copy_pos = 0;
+ return (100);
+ }
+
+ /* lzh_br_read_ahead() always try to fill the
+ * cache buffer up. In specific situation we
+ * are close to the end of the data, the cache
+ * buffer will not be full and thus we have to
+ * determine if the cache buffer has some bits
+ * as much as we need after lzh_br_read_ahead()
+ * failed. */
+ if (!lzh_br_read_ahead(strm, &bre,
+ lt_max_bits)) {
+ if (!last)
+ goto next_data;
+ /* Remaining bits are less than
+ * maximum bits(lt.max_bits) but maybe
+ * it still remains as much as we need,
+ * so we should try to use it with
+ * dummy bits. */
+ c = lzh_decode_huffman(lt,
+ lzh_br_bits_forced(&bre,
+ lt_max_bits));
+ lzh_br_consume(&bre, lt_bitlen[c]);
+ if (!lzh_br_has(&bre, 0))
+ goto failed;/* Over read. */
+ } else {
+ c = lzh_decode_huffman(lt,
+ lzh_br_bits(&bre, lt_max_bits));
+ lzh_br_consume(&bre, lt_bitlen[c]);
+ }
+ blocks_avail--;
+ if (c > UCHAR_MAX)
+ /* Current block is a match data. */
+ break;
+ /*
+ * 'c' is exactly a literal code.
+ */
+ /* Save a decoded code to reference it
+ * afterward. */
+ w_buff[w_pos] = c;
+ if (++w_pos >= w_size) {
+ w_pos = 0;
+ ds->w_remaining = w_size;
+ if (!lzh_copy_from_window(strm, ds))
+ goto next_data;
+ }
+ }
+ /* 'c' is the length of a match pattern we have
+ * already extracted, which has be stored in
+ * window(ds->w_buff). */
+ copy_len = c - (UCHAR_MAX + 1) + MINMATCH;
+ /* FALL THROUGH */
+ case ST_GET_POS_1:
+ /*
+ * Get a reference position.
+ */
+ if (!lzh_br_read_ahead(strm, &bre, pt_max_bits)) {
+ if (!last) {
+ state = ST_GET_POS_1;
+ ds->copy_len = copy_len;
+ goto next_data;
+ }
+ copy_pos = lzh_decode_huffman(pt,
+ lzh_br_bits_forced(&bre, pt_max_bits));
+ lzh_br_consume(&bre, pt_bitlen[copy_pos]);
+ if (!lzh_br_has(&bre, 0))
+ goto failed;/* Over read. */
+ } else {
+ copy_pos = lzh_decode_huffman(pt,
+ lzh_br_bits(&bre, pt_max_bits));
+ lzh_br_consume(&bre, pt_bitlen[copy_pos]);
+ }
+ /* FALL THROUGH */
+ case ST_GET_POS_2:
+ if (copy_pos > 1) {
+ /* We need an additional adjustment number to
+ * the position. */
+ int p = copy_pos - 1;
+ if (!lzh_br_read_ahead(strm, &bre, p)) {
+ if (last)
+ goto failed;/* Truncated data.*/
+ state = ST_GET_POS_2;
+ ds->copy_len = copy_len;
+ ds->copy_pos = copy_pos;
+ goto next_data;
+ }
+ copy_pos = (1 << p) + lzh_br_bits(&bre, p);
+ lzh_br_consume(&bre, p);
+ }
+ /* The position is actually a distance from the last
+ * code we had extracted and thus we have to convert
+ * it to a position of the window. */
+ copy_pos = (w_pos - copy_pos - 1) & w_mask;
+ /* FALL THROUGH */
+ case ST_COPY_DATA:
+ /*
+ * Copy `copy_len' bytes as extracted data from
+ * the window into the output buffer.
+ */
+ for (;;) {
+ int l;
+
+ l = copy_len;
+ if (copy_pos > w_pos) {
+ if (l > w_size - copy_pos)
+ l = w_size - copy_pos;
+ } else {
+ if (l > w_size - w_pos)
+ l = w_size - w_pos;
+ }
+ if ((copy_pos + l < w_pos)
+ || (w_pos + l < copy_pos)) {
+ /* No overlap. */
+ memcpy(w_buff + w_pos,
+ w_buff + copy_pos, l);
+ } else {
+ const unsigned char *s;
+ unsigned char *d;
+ int li;
+
+ d = w_buff + w_pos;
+ s = w_buff + copy_pos;
+ for (li = 0; li < l; li++)
+ d[li] = s[li];
+ }
+ w_pos = (w_pos + l) & w_mask;
+ if (w_pos == 0) {
+ ds->w_remaining = w_size;
+ if (!lzh_copy_from_window(strm, ds)) {
+ if (copy_len <= l)
+ state = ST_GET_LITERAL;
+ else {
+ state = ST_COPY_DATA;
+ ds->copy_len =
+ copy_len - l;
+ ds->copy_pos =
+ (copy_pos + l)
+ & w_mask;
+ }
+ goto next_data;
+ }
+ }
+ if (copy_len <= l)
+ /* A copy of current pattern ended. */
+ break;
+ copy_len -= l;
+ copy_pos = (copy_pos + l) & w_mask;
+ }
+ state = ST_GET_LITERAL;
+ break;
+ }
+ }
+failed:
+ return (ds->error = ARCHIVE_FAILED);
+next_data:
+ ds->br = bre;
+ ds->blocks_avail = blocks_avail;
+ ds->state = state;
+ ds->w_pos = w_pos;
+ return (ARCHIVE_OK);
+}
+
+static int
+lzh_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
+{
+ int bits;
+
+ if (hf->bitlen == NULL) {
+ hf->bitlen = malloc(len_size * sizeof(hf->bitlen[0]));
+ if (hf->bitlen == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ if (hf->tbl == NULL) {
+ if (tbl_bits < HTBL_BITS)
+ bits = tbl_bits;
+ else
+ bits = HTBL_BITS;
+ hf->tbl = malloc((1 << bits) * sizeof(hf->tbl[0]));
+ if (hf->tbl == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ if (hf->tree == NULL && tbl_bits > HTBL_BITS) {
+ hf->tree_avail = 1 << (tbl_bits - HTBL_BITS + 4);
+ hf->tree = malloc(hf->tree_avail * sizeof(hf->tree[0]));
+ if (hf->tree == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ hf->len_size = len_size;
+ hf->tbl_bits = tbl_bits;
+ return (ARCHIVE_OK);
+}
+
+static void
+lzh_huffman_free(struct huffman *hf)
+{
+ free(hf->bitlen);
+ free(hf->tbl);
+ free(hf->tree);
+}
+
+static int
+lzh_read_pt_bitlen(struct lzh_stream *strm, int start, int end)
+{
+ struct lzh_dec *ds = strm->ds;
+ struct lzh_br * br = &(ds->br);
+ int c, i;
+
+ for (i = start; i < end;) {
+ /*
+ * bit pattern the number we need
+ * 000 -> 0
+ * 001 -> 1
+ * 010 -> 2
+ * ...
+ * 110 -> 6
+ * 1110 -> 7
+ * 11110 -> 8
+ * ...
+ * 1111111111110 -> 16
+ */
+ if (!lzh_br_read_ahead(strm, br, 3))
+ return (i);
+ if ((c = lzh_br_bits(br, 3)) == 7) {
+ int d;
+ if (!lzh_br_read_ahead(strm, br, 13))
+ return (i);
+ d = lzh_br_bits(br, 13);
+ while (d & 0x200) {
+ c++;
+ d <<= 1;
+ }
+ if (c > 16)
+ return (-1);/* Invalid data. */
+ lzh_br_consume(br, c - 3);
+ } else
+ lzh_br_consume(br, 3);
+ ds->pt.bitlen[i++] = c;
+ ds->pt.freq[c]++;
+ }
+ return (i);
+}
+
+static int
+lzh_make_fake_table(struct huffman *hf, uint16_t c)
+{
+ if (c >= hf->len_size)
+ return (0);
+ hf->tbl[0] = c;
+ hf->max_bits = 0;
+ hf->shift_bits = 0;
+ hf->bitlen[hf->tbl[0]] = 0;
+ return (1);
+}
+
+/*
+ * Make a huffman coding table.
+ */
+static int
+lzh_make_huffman_table(struct huffman *hf)
+{
+ uint16_t *tbl;
+ const unsigned char *bitlen;
+ int bitptn[17], weight[17];
+ int i, maxbits = 0, ptn, tbl_size, w;
+ int diffbits, len_avail;
+
+ /*
+ * Initialize bit patterns.
+ */
+ ptn = 0;
+ for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {
+ bitptn[i] = ptn;
+ weight[i] = w;
+ if (hf->freq[i]) {
+ ptn += hf->freq[i] * w;
+ maxbits = i;
+ }
+ }
+ if (ptn != 0x10000 || maxbits > hf->tbl_bits)
+ return (0);/* Invalid */
+
+ hf->max_bits = maxbits;
+
+ /*
+ * Cut out extra bits which we won't house in the table.
+ * This preparation reduces the same calculation in the for-loop
+ * making the table.
+ */
+ if (maxbits < 16) {
+ int ebits = 16 - maxbits;
+ for (i = 1; i <= maxbits; i++) {
+ bitptn[i] >>= ebits;
+ weight[i] >>= ebits;
+ }
+ }
+ if (maxbits > HTBL_BITS) {
+ int htbl_max;
+ uint16_t *p;
+
+ diffbits = maxbits - HTBL_BITS;
+ for (i = 1; i <= HTBL_BITS; i++) {
+ bitptn[i] >>= diffbits;
+ weight[i] >>= diffbits;
+ }
+ htbl_max = bitptn[HTBL_BITS] +
+ weight[HTBL_BITS] * hf->freq[HTBL_BITS];
+ p = &(hf->tbl[htbl_max]);
+ while (p < &hf->tbl[1U<<HTBL_BITS])
+ *p++ = 0;
+ } else
+ diffbits = 0;
+ hf->shift_bits = diffbits;
+
+ /*
+ * Make the table.
+ */
+ tbl_size = 1 << HTBL_BITS;
+ tbl = hf->tbl;
+ bitlen = hf->bitlen;
+ len_avail = hf->len_avail;
+ hf->tree_used = 0;
+ for (i = 0; i < len_avail; i++) {
+ uint16_t *p;
+ int len, cnt;
+ uint16_t bit;
+ int extlen;
+ struct htree_t *ht;
+
+ if (bitlen[i] == 0)
+ continue;
+ /* Get a bit pattern */
+ len = bitlen[i];
+ ptn = bitptn[len];
+ cnt = weight[len];
+ if (len <= HTBL_BITS) {
+ /* Calculate next bit pattern */
+ if ((bitptn[len] = ptn + cnt) > tbl_size)
+ return (0);/* Invalid */
+ /* Update the table */
+ p = &(tbl[ptn]);
+ while (--cnt >= 0)
+ p[cnt] = (uint16_t)i;
+ continue;
+ }
+
+ /*
+ * A bit length is too big to be housed to a direct table,
+ * so we use a tree model for its extra bits.
+ */
+ bitptn[len] = ptn + cnt;
+ bit = 1U << (diffbits -1);
+ extlen = len - HTBL_BITS;
+
+ p = &(tbl[ptn >> diffbits]);
+ if (*p == 0) {
+ *p = len_avail + hf->tree_used;
+ ht = &(hf->tree[hf->tree_used++]);
+ if (hf->tree_used > hf->tree_avail)
+ return (0);/* Invalid */
+ ht->left = 0;
+ ht->right = 0;
+ } else {
+ if (*p < len_avail ||
+ *p >= (len_avail + hf->tree_used))
+ return (0);/* Invalid */
+ ht = &(hf->tree[*p - len_avail]);
+ }
+ while (--extlen > 0) {
+ if (ptn & bit) {
+ if (ht->left < len_avail) {
+ ht->left = len_avail + hf->tree_used;
+ ht = &(hf->tree[hf->tree_used++]);
+ if (hf->tree_used > hf->tree_avail)
+ return (0);/* Invalid */
+ ht->left = 0;
+ ht->right = 0;
+ } else {
+ ht = &(hf->tree[ht->left - len_avail]);
+ }
+ } else {
+ if (ht->right < len_avail) {
+ ht->right = len_avail + hf->tree_used;
+ ht = &(hf->tree[hf->tree_used++]);
+ if (hf->tree_used > hf->tree_avail)
+ return (0);/* Invalid */
+ ht->left = 0;
+ ht->right = 0;
+ } else {
+ ht = &(hf->tree[ht->right - len_avail]);
+ }
+ }
+ bit >>= 1;
+ }
+ if (ptn & bit) {
+ if (ht->left != 0)
+ return (0);/* Invalid */
+ ht->left = (uint16_t)i;
+ } else {
+ if (ht->right != 0)
+ return (0);/* Invalid */
+ ht->right = (uint16_t)i;
+ }
+ }
+ return (1);
+}
+
+static int
+lzh_decode_huffman_tree(struct huffman *hf, unsigned rbits, int c)
+{
+ struct htree_t *ht;
+ int extlen;
+
+ ht = hf->tree;
+ extlen = hf->shift_bits;
+ while (c >= hf->len_avail) {
+ c -= hf->len_avail;
+ if (extlen-- <= 0 || c >= hf->tree_used)
+ return (0);
+ if (rbits & (1U << extlen))
+ c = ht[c].left;
+ else
+ c = ht[c].right;
+ }
+ return (c);
+}
+
+static inline int
+lzh_decode_huffman(struct huffman *hf, unsigned rbits)
+{
+ int c;
+ /*
+ * At first search an index table for a bit pattern.
+ * If it fails, search a huffman tree for.
+ */
+ c = hf->tbl[rbits >> hf->shift_bits];
+ if (c < hf->len_avail)
+ return (c);
+ /* This bit pattern needs to be found out at a huffman tree. */
+ return (lzh_decode_huffman_tree(hf, rbits, c));
+}
+
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_read_support_format_rar.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_read_support_format_rar.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,2576 @@
+/*-
+* Copyright (c) 2003-2007 Tim Kientzle
+* Copyright (c) 2011 Andres Mejia
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "archive_platform.h"
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <time.h>
+#include <limits.h>
+#ifdef HAVE_ZLIB_H
+#include <zlib.h> /* crc32 */
+#endif
+
+#include "archive.h"
+#ifndef HAVE_ZLIB_H
+#include "archive_crc32.h"
+#endif
+#include "archive_endian.h"
+#include "archive_entry.h"
+#include "archive_entry_locale.h"
+#include "archive_ppmd7_private.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+/* RAR signature, also known as the mark header */
+#define RAR_SIGNATURE "\x52\x61\x72\x21\x1A\x07\x00"
+
+/* Header types */
+#define MARK_HEAD 0x72
+#define MAIN_HEAD 0x73
+#define FILE_HEAD 0x74
+#define COMM_HEAD 0x75
+#define AV_HEAD 0x76
+#define SUB_HEAD 0x77
+#define PROTECT_HEAD 0x78
+#define SIGN_HEAD 0x79
+#define NEWSUB_HEAD 0x7a
+#define ENDARC_HEAD 0x7b
+
+/* Main Header Flags */
+#define MHD_VOLUME 0x0001
+#define MHD_COMMENT 0x0002
+#define MHD_LOCK 0x0004
+#define MHD_SOLID 0x0008
+#define MHD_NEWNUMBERING 0x0010
+#define MHD_AV 0x0020
+#define MHD_PROTECT 0x0040
+#define MHD_PASSWORD 0x0080
+#define MHD_FIRSTVOLUME 0x0100
+#define MHD_ENCRYPTVER 0x0200
+
+/* Flags common to all headers */
+#define HD_MARKDELETION 0x4000
+#define HD_ADD_SIZE_PRESENT 0x8000
+
+/* File Header Flags */
+#define FHD_SPLIT_BEFORE 0x0001
+#define FHD_SPLIT_AFTER 0x0002
+#define FHD_PASSWORD 0x0004
+#define FHD_COMMENT 0x0008
+#define FHD_SOLID 0x0010
+#define FHD_LARGE 0x0100
+#define FHD_UNICODE 0x0200
+#define FHD_SALT 0x0400
+#define FHD_VERSION 0x0800
+#define FHD_EXTTIME 0x1000
+#define FHD_EXTFLAGS 0x2000
+
+/* File dictionary sizes */
+#define DICTIONARY_SIZE_64 0x00
+#define DICTIONARY_SIZE_128 0x20
+#define DICTIONARY_SIZE_256 0x40
+#define DICTIONARY_SIZE_512 0x60
+#define DICTIONARY_SIZE_1024 0x80
+#define DICTIONARY_SIZE_2048 0xA0
+#define DICTIONARY_SIZE_4096 0xC0
+#define FILE_IS_DIRECTORY 0xE0
+#define DICTIONARY_MASK FILE_IS_DIRECTORY
+
+/* OS Flags */
+#define OS_MSDOS 0
+#define OS_OS2 1
+#define OS_WIN32 2
+#define OS_UNIX 3
+#define OS_MAC_OS 4
+#define OS_BEOS 5
+
+/* Compression Methods */
+#define COMPRESS_METHOD_STORE 0x30
+/* LZSS */
+#define COMPRESS_METHOD_FASTEST 0x31
+#define COMPRESS_METHOD_FAST 0x32
+#define COMPRESS_METHOD_NORMAL 0x33
+/* PPMd Variant H */
+#define COMPRESS_METHOD_GOOD 0x34
+#define COMPRESS_METHOD_BEST 0x35
+
+#define CRC_POLYNOMIAL 0xEDB88320
+
+#define NS_UNIT 10000000
+
+#define DICTIONARY_MAX_SIZE 0x400000
+
+#define MAINCODE_SIZE 299
+#define OFFSETCODE_SIZE 60
+#define LOWOFFSETCODE_SIZE 17
+#define LENGTHCODE_SIZE 28
+#define HUFFMAN_TABLE_SIZE \
+ MAINCODE_SIZE + OFFSETCODE_SIZE + LOWOFFSETCODE_SIZE + LENGTHCODE_SIZE
+
+#define MAX_SYMBOL_LENGTH 0xF
+#define MAX_SYMBOLS 20
+
+/*
+ * Considering L1,L2 cache miss and a calling of write system-call,
+ * the best size of the output buffer(uncompressed buffer) is 128K.
+ * If the structure of extracting process is changed, this value
+ * might be researched again.
+ */
+#define UNP_BUFFER_SIZE (128 * 1024)
+
+/* Define this here for non-Windows platforms */
+#if !((defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__))
+#define FILE_ATTRIBUTE_DIRECTORY 0x10
+#endif
+
+/* Fields common to all headers */
+struct rar_header
+{
+ char crc[2];
+ char type;
+ char flags[2];
+ char size[2];
+};
+
+/* Fields common to all file headers */
+struct rar_file_header
+{
+ char pack_size[4];
+ char unp_size[4];
+ char host_os;
+ char file_crc[4];
+ char file_time[4];
+ char unp_ver;
+ char method;
+ char name_size[2];
+ char file_attr[4];
+};
+
+struct huffman_tree_node
+{
+ int branches[2];
+};
+
+struct huffman_table_entry
+{
+ unsigned int length;
+ int value;
+};
+
+struct huffman_code
+{
+ struct huffman_tree_node *tree;
+ int numentries;
+ int minlength;
+ int maxlength;
+ int tablesize;
+ struct huffman_table_entry *table;
+};
+
+struct lzss
+{
+ unsigned char *window;
+ int mask;
+ int64_t position;
+};
+
+struct rar
+{
+ /* Entries from main RAR header */
+ unsigned main_flags;
+ unsigned long file_crc;
+ char reserved1[2];
+ char reserved2[4];
+ char encryptver;
+
+ /* File header entries */
+ char compression_method;
+ unsigned file_flags;
+ int64_t packed_size;
+ int64_t unp_size;
+ time_t mtime;
+ long mnsec;
+ mode_t mode;
+ char *filename;
+ size_t filename_allocated;
+
+ /* File header optional entries */
+ char salt[8];
+ time_t atime;
+ long ansec;
+ time_t ctime;
+ long cnsec;
+ time_t arctime;
+ long arcnsec;
+
+ /* Fields to help with tracking decompression of files. */
+ int64_t bytes_unconsumed;
+ int64_t bytes_remaining;
+ int64_t bytes_uncopied;
+ int64_t offset;
+ int64_t offset_outgoing;
+ char valid;
+ unsigned int unp_offset;
+ unsigned int unp_buffer_size;
+ unsigned char *unp_buffer;
+ unsigned int dictionary_size;
+ char start_new_block;
+ char entry_eof;
+ unsigned long crc_calculated;
+ int found_first_header;
+
+ /* LZSS members */
+ struct huffman_code maincode;
+ struct huffman_code offsetcode;
+ struct huffman_code lowoffsetcode;
+ struct huffman_code lengthcode;
+ unsigned char lengthtable[HUFFMAN_TABLE_SIZE];
+ struct lzss lzss;
+ char output_last_match;
+ unsigned int lastlength;
+ unsigned int lastoffset;
+ unsigned int oldoffset[4];
+ unsigned int lastlowoffset;
+ unsigned int numlowoffsetrepeats;
+ int64_t filterstart;
+ char start_new_table;
+
+ /* PPMd Variant H members */
+ char ppmd_valid;
+ char ppmd_eod;
+ char is_ppmd_block;
+ int ppmd_escape;
+ CPpmd7 ppmd7_context;
+ CPpmd7z_RangeDec range_dec;
+ IByteIn bytein;
+
+ /*
+ * String conversion object.
+ */
+ int init_default_conversion;
+ struct archive_string_conv *sconv_default;
+ struct archive_string_conv *opt_sconv;
+ struct archive_string_conv *sconv_utf8;
+ struct archive_string_conv *sconv_utf16be;
+
+ /*
+ * Bit stream reader.
+ */
+ struct rar_br {
+#define CACHE_TYPE uint64_t
+#define CACHE_BITS (8 * sizeof(CACHE_TYPE))
+ /* Cache buffer. */
+ CACHE_TYPE cache_buffer;
+ /* Indicates how many bits avail in cache_buffer. */
+ int cache_avail;
+ ssize_t avail_in;
+ const unsigned char *next_in;
+ } br;
+};
+
+static int archive_read_format_rar_bid(struct archive_read *, int);
+static int archive_read_format_rar_options(struct archive_read *,
+ const char *, const char *);
+static int archive_read_format_rar_read_header(struct archive_read *,
+ struct archive_entry *);
+static int archive_read_format_rar_read_data(struct archive_read *,
+ const void **, size_t *, int64_t *);
+static int archive_read_format_rar_read_data_skip(struct archive_read *a);
+static int archive_read_format_rar_cleanup(struct archive_read *);
+
+/* Support functions */
+static int read_header(struct archive_read *, struct archive_entry *, char);
+static time_t get_time(int);
+static int read_exttime(const char *, struct rar *, const char *);
+static int read_symlink_stored(struct archive_read *, struct archive_entry *,
+ struct archive_string_conv *);
+static int read_data_stored(struct archive_read *, const void **, size_t *,
+ int64_t *);
+static int read_data_compressed(struct archive_read *, const void **, size_t *,
+ int64_t *);
+static int rar_br_preparation(struct archive_read *, struct rar_br *);
+static int parse_codes(struct archive_read *);
+static void free_codes(struct archive_read *);
+static int read_next_symbol(struct archive_read *, struct huffman_code *);
+static int create_code(struct archive_read *, struct huffman_code *,
+ unsigned char *, int, char);
+static int add_value(struct archive_read *, struct huffman_code *, int, int,
+ int);
+static int new_node(struct huffman_code *);
+static int make_table(struct archive_read *, struct huffman_code *);
+static int make_table_recurse(struct archive_read *, struct huffman_code *, int,
+ struct huffman_table_entry *, int, int);
+static int64_t expand(struct archive_read *, int64_t);
+static int copy_from_lzss_window(struct archive_read *, const void **,
+ int64_t, int);
+
+/*
+ * Bit stream reader.
+ */
+/* Check that the cache buffer has enough bits. */
+#define rar_br_has(br, n) ((br)->cache_avail >= n)
+/* Get compressed data by bit. */
+#define rar_br_bits(br, n) \
+ (((uint32_t)((br)->cache_buffer >> \
+ ((br)->cache_avail - (n)))) & cache_masks[n])
+#define rar_br_bits_forced(br, n) \
+ (((uint32_t)((br)->cache_buffer << \
+ ((n) - (br)->cache_avail))) & cache_masks[n])
+/* Read ahead to make sure the cache buffer has enough compressed data we
+ * will use.
+ * True : completed, there is enough data in the cache buffer.
+ * False : there is no data in the stream. */
+#define rar_br_read_ahead(a, br, n) \
+ ((rar_br_has(br, (n)) || rar_br_fillup(a, br)) || rar_br_has(br, (n)))
+/* Notify how many bits we consumed. */
+#define rar_br_consume(br, n) ((br)->cache_avail -= (n))
+#define rar_br_consume_unalined_bits(br) ((br)->cache_avail &= ~7)
+
+static const uint32_t cache_masks[] = {
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007,
+ 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
+ 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
+ 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
+ 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
+ 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
+ 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
+ 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+/*
+ * Shift away used bits in the cache data and fill it up with following bits.
+ * Call this when cache buffer does not have enough bits you need.
+ *
+ * Returns 1 if the cache buffer is full.
+ * Returns 0 if the cache buffer is not full; input buffer is empty.
+ */
+static int
+rar_br_fillup(struct archive_read *a, struct rar_br *br)
+{
+ struct rar *rar = (struct rar *)(a->format->data);
+ int n = CACHE_BITS - br->cache_avail;
+
+ for (;;) {
+ switch (n >> 3) {
+ case 8:
+ if (br->avail_in >= 8) {
+ br->cache_buffer =
+ ((uint64_t)br->next_in[0]) << 56 |
+ ((uint64_t)br->next_in[1]) << 48 |
+ ((uint64_t)br->next_in[2]) << 40 |
+ ((uint64_t)br->next_in[3]) << 32 |
+ ((uint32_t)br->next_in[4]) << 24 |
+ ((uint32_t)br->next_in[5]) << 16 |
+ ((uint32_t)br->next_in[6]) << 8 |
+ (uint32_t)br->next_in[7];
+ br->next_in += 8;
+ br->avail_in -= 8;
+ br->cache_avail += 8 * 8;
+ rar->bytes_unconsumed += 8;
+ rar->bytes_remaining -= 8;
+ return (1);
+ }
+ break;
+ case 7:
+ if (br->avail_in >= 7) {
+ br->cache_buffer =
+ (br->cache_buffer << 56) |
+ ((uint64_t)br->next_in[0]) << 48 |
+ ((uint64_t)br->next_in[1]) << 40 |
+ ((uint64_t)br->next_in[2]) << 32 |
+ ((uint32_t)br->next_in[3]) << 24 |
+ ((uint32_t)br->next_in[4]) << 16 |
+ ((uint32_t)br->next_in[5]) << 8 |
+ (uint32_t)br->next_in[6];
+ br->next_in += 7;
+ br->avail_in -= 7;
+ br->cache_avail += 7 * 8;
+ rar->bytes_unconsumed += 7;
+ rar->bytes_remaining -= 7;
+ return (1);
+ }
+ break;
+ case 6:
+ if (br->avail_in >= 6) {
+ br->cache_buffer =
+ (br->cache_buffer << 48) |
+ ((uint64_t)br->next_in[0]) << 40 |
+ ((uint64_t)br->next_in[1]) << 32 |
+ ((uint32_t)br->next_in[2]) << 24 |
+ ((uint32_t)br->next_in[3]) << 16 |
+ ((uint32_t)br->next_in[4]) << 8 |
+ (uint32_t)br->next_in[5];
+ br->next_in += 6;
+ br->avail_in -= 6;
+ br->cache_avail += 6 * 8;
+ rar->bytes_unconsumed += 6;
+ rar->bytes_remaining -= 6;
+ return (1);
+ }
+ break;
+ case 0:
+ /* We have enough compressed data in
+ * the cache buffer.*/
+ return (1);
+ default:
+ break;
+ }
+ if (br->avail_in <= 0) {
+
+ if (rar->bytes_unconsumed > 0) {
+ /* Consume as much as the decompressor
+ * actually used. */
+ __archive_read_consume(a, rar->bytes_unconsumed);
+ rar->bytes_unconsumed = 0;
+ }
+ br->next_in = __archive_read_ahead(a, 1, &(br->avail_in));
+ if (br->next_in == NULL)
+ return (0);
+ if (br->avail_in > rar->bytes_remaining)
+ br->avail_in = rar->bytes_remaining;
+ if (br->avail_in == 0)
+ return (0);
+ }
+ br->cache_buffer =
+ (br->cache_buffer << 8) | *br->next_in++;
+ br->avail_in--;
+ br->cache_avail += 8;
+ n -= 8;
+ rar->bytes_unconsumed++;
+ rar->bytes_remaining--;
+ }
+}
+
+static int
+rar_br_preparation(struct archive_read *a, struct rar_br *br)
+{
+ struct rar *rar = (struct rar *)(a->format->data);
+
+ if (rar->bytes_remaining > 0) {
+ br->next_in = __archive_read_ahead(a, 1, &(br->avail_in));
+ if (br->next_in == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated RAR file data");
+ return (ARCHIVE_FATAL);
+ }
+ if (br->avail_in > rar->bytes_remaining)
+ br->avail_in = rar->bytes_remaining;
+ if (br->cache_avail == 0)
+ (void)rar_br_fillup(a, br);
+ }
+ return (ARCHIVE_OK);
+}
+
+/* Find last bit set */
+static inline int
+rar_fls(unsigned int word)
+{
+ word |= (word >> 1);
+ word |= (word >> 2);
+ word |= (word >> 4);
+ word |= (word >> 8);
+ word |= (word >> 16);
+ return word - (word >> 1);
+}
+
+/* LZSS functions */
+static inline int64_t
+lzss_position(struct lzss *lzss)
+{
+ return lzss->position;
+}
+
+static inline int
+lzss_mask(struct lzss *lzss)
+{
+ return lzss->mask;
+}
+
+static inline int
+lzss_size(struct lzss *lzss)
+{
+ return lzss->mask + 1;
+}
+
+static inline int
+lzss_offset_for_position(struct lzss *lzss, int64_t pos)
+{
+ return pos & lzss->mask;
+}
+
+static inline unsigned char *
+lzss_pointer_for_position(struct lzss *lzss, int64_t pos)
+{
+ return &lzss->window[lzss_offset_for_position(lzss, pos)];
+}
+
+static inline int
+lzss_current_offset(struct lzss *lzss)
+{
+ return lzss_offset_for_position(lzss, lzss->position);
+}
+
+static inline uint8_t *
+lzss_current_pointer(struct lzss *lzss)
+{
+ return lzss_pointer_for_position(lzss, lzss->position);
+}
+
+static inline void
+lzss_emit_literal(struct rar *rar, uint8_t literal)
+{
+ *lzss_current_pointer(&rar->lzss) = literal;
+ rar->lzss.position++;
+}
+
+static inline void
+lzss_emit_match(struct rar *rar, int offset, int length)
+{
+ int dstoffs = lzss_current_offset(&rar->lzss);
+ int srcoffs = (dstoffs - offset) & lzss_mask(&rar->lzss);
+ int l, li, remaining;
+ unsigned char *d, *s;
+
+ remaining = length;
+ while (remaining > 0) {
+ l = remaining;
+ if (dstoffs > srcoffs) {
+ if (l > lzss_size(&rar->lzss) - dstoffs)
+ l = lzss_size(&rar->lzss) - dstoffs;
+ } else {
+ if (l > lzss_size(&rar->lzss) - srcoffs)
+ l = lzss_size(&rar->lzss) - srcoffs;
+ }
+ d = &(rar->lzss.window[dstoffs]);
+ s = &(rar->lzss.window[srcoffs]);
+ if ((dstoffs + l < srcoffs) || (srcoffs + l < dstoffs))
+ memcpy(d, s, l);
+ else {
+ for (li = 0; li < l; li++)
+ d[li] = s[li];
+ }
+ remaining -= l;
+ dstoffs = (dstoffs + l) & lzss_mask(&(rar->lzss));
+ srcoffs = (srcoffs + l) & lzss_mask(&(rar->lzss));
+ }
+ rar->lzss.position += length;
+}
+
+static void *
+ppmd_alloc(void *p, size_t size)
+{
+ (void)p;
+ return malloc(size);
+}
+static void
+ppmd_free(void *p, void *address)
+{
+ (void)p;
+ free(address);
+}
+static ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
+
+static Byte
+ppmd_read(void *p)
+{
+ struct archive_read *a = ((IByteIn*)p)->a;
+ struct rar *rar = (struct rar *)(a->format->data);
+ struct rar_br *br = &(rar->br);
+ Byte b;
+ if (!rar_br_read_ahead(a, br, 8))
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated RAR file data");
+ rar->valid = 0;
+ return 0;
+ }
+ b = rar_br_bits(br, 8);
+ rar_br_consume(br, 8);
+ return b;
+}
+
+int
+archive_read_support_format_rar(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct rar *rar;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
+ "archive_read_support_format_rar");
+
+ rar = (struct rar *)malloc(sizeof(*rar));
+ if (rar == NULL)
+ {
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate rar data");
+ return (ARCHIVE_FATAL);
+ }
+ memset(rar, 0, sizeof(*rar));
+
+ r = __archive_read_register_format(a,
+ rar,
+ "rar",
+ archive_read_format_rar_bid,
+ archive_read_format_rar_options,
+ archive_read_format_rar_read_header,
+ archive_read_format_rar_read_data,
+ archive_read_format_rar_read_data_skip,
+ archive_read_format_rar_cleanup);
+
+ if (r != ARCHIVE_OK)
+ free(rar);
+ return (r);
+}
+
+static int
+archive_read_format_rar_bid(struct archive_read *a, int best_bid)
+{
+ const char *p;
+
+ /* If there's already a bid > 30, we'll never win. */
+ if (best_bid > 30)
+ return (-1);
+
+ if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)
+ return (-1);
+
+ if (memcmp(p, RAR_SIGNATURE, 7) == 0)
+ return (30);
+
+ if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
+ /* This is a PE file */
+ ssize_t offset = 0x10000;
+ ssize_t window = 4096;
+ ssize_t bytes_avail;
+ while (offset + window <= (1024 * 128)) {
+ const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail);
+ if (buff == NULL) {
+ /* Remaining bytes are less than window. */
+ window >>= 1;
+ if (window < 0x40)
+ return (0);
+ continue;
+ }
+ p = buff + offset;
+ while (p + 7 < buff + bytes_avail) {
+ if (memcmp(p, RAR_SIGNATURE, 7) == 0)
+ return (30);
+ p += 0x10;
+ }
+ offset = p - buff;
+ }
+ }
+ return (0);
+}
+
+static int
+skip_sfx(struct archive_read *a)
+{
+ const void *h;
+ const char *p, *q;
+ size_t skip, total;
+ ssize_t bytes, window;
+
+ total = 0;
+ window = 4096;
+ while (total + window <= (1024 * 128)) {
+ h = __archive_read_ahead(a, window, &bytes);
+ if (h == NULL) {
+ /* Remaining bytes are less than window. */
+ window >>= 1;
+ if (window < 0x40)
+ goto fatal;
+ continue;
+ }
+ if (bytes < 0x40)
+ goto fatal;
+ p = h;
+ q = p + bytes;
+
+ /*
+ * Scan ahead until we find something that looks
+ * like the RAR header.
+ */
+ while (p + 7 < q) {
+ if (memcmp(p, RAR_SIGNATURE, 7) == 0) {
+ skip = p - (const char *)h;
+ __archive_read_consume(a, skip);
+ return (ARCHIVE_OK);
+ }
+ p += 0x10;
+ }
+ skip = p - (const char *)h;
+ __archive_read_consume(a, skip);
+ total += skip;
+ }
+fatal:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Couldn't find out RAR header");
+ return (ARCHIVE_FATAL);
+}
+
+static int
+archive_read_format_rar_options(struct archive_read *a,
+ const char *key, const char *val)
+{
+ struct rar *rar;
+ int ret = ARCHIVE_FAILED;
+
+ rar = (struct rar *)(a->format->data);
+ if (strcmp(key, "hdrcharset") == 0) {
+ if (val == NULL || val[0] == 0)
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "rar: hdrcharset option needs a character-set name");
+ else {
+ rar->opt_sconv =
+ archive_string_conversion_from_charset(
+ &a->archive, val, 0);
+ if (rar->opt_sconv != NULL)
+ ret = ARCHIVE_OK;
+ else
+ ret = ARCHIVE_FATAL;
+ }
+ return (ret);
+ }
+
+ /* Note: The "warn" return is just to inform the options
+ * supervisor that we didn't handle it. It will generate
+ * a suitable error if no one used this option. */
+ return (ARCHIVE_WARN);
+}
+
+static int
+archive_read_format_rar_read_header(struct archive_read *a,
+ struct archive_entry *entry)
+{
+ const void *h;
+ const char *p;
+ struct rar *rar;
+ size_t skip;
+ char head_type;
+ int ret;
+ unsigned flags;
+
+ a->archive.archive_format = ARCHIVE_FORMAT_RAR;
+ if (a->archive.archive_format_name == NULL)
+ a->archive.archive_format_name = "RAR";
+
+ rar = (struct rar *)(a->format->data);
+
+ /* RAR files can be generated without EOF headers, so return ARCHIVE_EOF if
+ * this fails.
+ */
+ if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
+ return (ARCHIVE_EOF);
+
+ p = h;
+ if (rar->found_first_header == 0 &&
+ ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0)) {
+ /* This is an executable ? Must be self-extracting... */
+ ret = skip_sfx(a);
+ if (ret < ARCHIVE_WARN)
+ return (ret);
+ }
+ rar->found_first_header = 1;
+
+ while (1)
+ {
+ unsigned long crc32_val;
+
+ if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
+ return (ARCHIVE_FATAL);
+ p = h;
+
+ head_type = p[2];
+ switch(head_type)
+ {
+ case MARK_HEAD:
+ if (memcmp(p, RAR_SIGNATURE, 7) != 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid marker header");
+ return (ARCHIVE_FATAL);
+ }
+ __archive_read_consume(a, 7);
+ break;
+
+ case MAIN_HEAD:
+ rar->main_flags = archive_le16dec(p + 3);
+ skip = archive_le16dec(p + 5);
+ if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid header size");
+ return (ARCHIVE_FATAL);
+ }
+ if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)
+ return (ARCHIVE_FATAL);
+ p = h;
+ memcpy(rar->reserved1, p + 7, sizeof(rar->reserved1));
+ memcpy(rar->reserved2, p + 7 + sizeof(rar->reserved1),
+ sizeof(rar->reserved2));
+ if (rar->main_flags & MHD_ENCRYPTVER) {
+ if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)+1) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid header size");
+ return (ARCHIVE_FATAL);
+ }
+ rar->encryptver = *(p + 7 + sizeof(rar->reserved1) +
+ sizeof(rar->reserved2));
+ }
+
+ if (rar->main_flags & MHD_VOLUME ||
+ rar->main_flags & MHD_FIRSTVOLUME)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "RAR volume support unavailable.");
+ return (ARCHIVE_FATAL);
+ }
+ if (rar->main_flags & MHD_PASSWORD)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "RAR encryption support unavailable.");
+ return (ARCHIVE_FATAL);
+ }
+
+ crc32_val = crc32(0, (const unsigned char *)p + 2, skip - 2);
+ if ((crc32_val & 0xffff) != archive_le16dec(p)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Header CRC error");
+ return (ARCHIVE_FATAL);
+ }
+ __archive_read_consume(a, skip);
+ break;
+
+ case FILE_HEAD:
+ return read_header(a, entry, head_type);
+
+ case COMM_HEAD:
+ case AV_HEAD:
+ case SUB_HEAD:
+ case PROTECT_HEAD:
+ case SIGN_HEAD:
+ flags = archive_le16dec(p + 3);
+ skip = archive_le16dec(p + 5);
+ if (skip < 7) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid header size");
+ return (ARCHIVE_FATAL);
+ }
+ if (skip > 7) {
+ if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)
+ return (ARCHIVE_FATAL);
+ p = h;
+ }
+ if (flags & HD_ADD_SIZE_PRESENT)
+ {
+ if (skip < 7 + 4) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid header size");
+ return (ARCHIVE_FATAL);
+ }
+ skip += archive_le32dec(p + 7);
+ if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)
+ return (ARCHIVE_FATAL);
+ p = h;
+ }
+
+ crc32_val = crc32(0, (const unsigned char *)p + 2, skip - 2);
+ if ((crc32_val & 0xffff) != archive_le16dec(p)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Header CRC error");
+ return (ARCHIVE_FATAL);
+ }
+ __archive_read_consume(a, skip);
+ break;
+
+ case NEWSUB_HEAD:
+ if ((ret = read_header(a, entry, head_type)) < ARCHIVE_WARN)
+ return ret;
+ break;
+
+ case ENDARC_HEAD:
+ return (ARCHIVE_EOF);
+
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Bad RAR file");
+ return (ARCHIVE_FATAL);
+ }
+ }
+}
+
+static int
+archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
+ size_t *size, int64_t *offset)
+{
+ struct rar *rar = (struct rar *)(a->format->data);
+ int ret;
+
+ if (rar->bytes_unconsumed > 0) {
+ /* Consume as much as the decompressor actually used. */
+ __archive_read_consume(a, rar->bytes_unconsumed);
+ rar->bytes_unconsumed = 0;
+ }
+
+ if (rar->entry_eof) {
+ *buff = NULL;
+ *size = 0;
+ *offset = rar->offset;
+ return (ARCHIVE_EOF);
+ }
+
+ switch (rar->compression_method)
+ {
+ case COMPRESS_METHOD_STORE:
+ ret = read_data_stored(a, buff, size, offset);
+ break;
+
+ case COMPRESS_METHOD_FASTEST:
+ case COMPRESS_METHOD_FAST:
+ case COMPRESS_METHOD_NORMAL:
+ case COMPRESS_METHOD_GOOD:
+ case COMPRESS_METHOD_BEST:
+ ret = read_data_compressed(a, buff, size, offset);
+ if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN)
+ __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
+ break;
+
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unsupported compression method for RAR file.");
+ ret = ARCHIVE_FATAL;
+ break;
+ }
+ return (ret);
+}
+
+static int
+archive_read_format_rar_read_data_skip(struct archive_read *a)
+{
+ struct rar *rar;
+ int64_t bytes_skipped;
+
+ rar = (struct rar *)(a->format->data);
+
+ if (rar->bytes_unconsumed > 0) {
+ /* Consume as much as the decompressor actually used. */
+ __archive_read_consume(a, rar->bytes_unconsumed);
+ rar->bytes_unconsumed = 0;
+ }
+
+ if (rar->bytes_remaining > 0) {
+ bytes_skipped = __archive_read_consume(a, rar->bytes_remaining);
+ if (bytes_skipped < 0)
+ return (ARCHIVE_FATAL);
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_rar_cleanup(struct archive_read *a)
+{
+ struct rar *rar;
+
+ rar = (struct rar *)(a->format->data);
+ free_codes(a);
+ free(rar->filename);
+ free(rar->unp_buffer);
+ free(rar->lzss.window);
+ __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
+ free(rar);
+ (a->format->data) = NULL;
+ return (ARCHIVE_OK);
+}
+
+static int
+read_header(struct archive_read *a, struct archive_entry *entry,
+ char head_type)
+{
+ const void *h;
+ const char *p, *endp;
+ struct rar *rar;
+ struct rar_header rar_header;
+ struct rar_file_header file_header;
+ int64_t header_size;
+ unsigned filename_size, end;
+ char *filename;
+ char *strp;
+ char packed_size[8];
+ char unp_size[8];
+ int ttime;
+ struct archive_string_conv *sconv, *fn_sconv;
+ unsigned long crc32_val;
+ int ret = (ARCHIVE_OK), ret2;
+
+ rar = (struct rar *)(a->format->data);
+
+ /* Setup a string conversion object for non-rar-unicode filenames. */
+ sconv = rar->opt_sconv;
+ if (sconv == NULL) {
+ if (!rar->init_default_conversion) {
+ rar->sconv_default =
+ archive_string_default_conversion_for_read(
+ &(a->archive));
+ rar->init_default_conversion = 1;
+ }
+ sconv = rar->sconv_default;
+ }
+
+
+ if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
+ return (ARCHIVE_FATAL);
+ p = h;
+ memcpy(&rar_header, p, sizeof(rar_header));
+ rar->file_flags = archive_le16dec(rar_header.flags);
+ header_size = archive_le16dec(rar_header.size);
+ if (header_size < (int64_t)sizeof(file_header) + 7) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid header size");
+ return (ARCHIVE_FATAL);
+ }
+ crc32_val = crc32(0, (const unsigned char *)p + 2, 7 - 2);
+ __archive_read_consume(a, 7);
+
+ if (!(rar->file_flags & FHD_SOLID))
+ {
+ rar->compression_method = 0;
+ rar->packed_size = 0;
+ rar->unp_size = 0;
+ rar->mtime = 0;
+ rar->ctime = 0;
+ rar->atime = 0;
+ rar->arctime = 0;
+ rar->mode = 0;
+ memset(&rar->salt, 0, sizeof(rar->salt));
+ rar->atime = 0;
+ rar->ansec = 0;
+ rar->ctime = 0;
+ rar->cnsec = 0;
+ rar->mtime = 0;
+ rar->mnsec = 0;
+ rar->arctime = 0;
+ rar->arcnsec = 0;
+ }
+ else
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "RAR solid archive support unavailable.");
+ return (ARCHIVE_FATAL);
+ }
+
+ if ((h = __archive_read_ahead(a, header_size - 7, NULL)) == NULL)
+ return (ARCHIVE_FATAL);
+
+ /* File Header CRC check. */
+ crc32_val = crc32(crc32_val, h, header_size - 7);
+ if ((crc32_val & 0xffff) != archive_le16dec(rar_header.crc)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Header CRC error");
+ return (ARCHIVE_FATAL);
+ }
+ /* If no CRC error, Go on parsing File Header. */
+ p = h;
+ endp = p + header_size - 7;
+ memcpy(&file_header, p, sizeof(file_header));
+ p += sizeof(file_header);
+
+ rar->compression_method = file_header.method;
+
+ ttime = archive_le32dec(file_header.file_time);
+ rar->mtime = get_time(ttime);
+
+ rar->file_crc = archive_le32dec(file_header.file_crc);
+
+ if (rar->file_flags & FHD_PASSWORD)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "RAR encryption support unavailable.");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (rar->file_flags & FHD_LARGE)
+ {
+ memcpy(packed_size, file_header.pack_size, 4);
+ memcpy(packed_size + 4, p, 4); /* High pack size */
+ p += 4;
+ memcpy(unp_size, file_header.unp_size, 4);
+ memcpy(unp_size + 4, p, 4); /* High unpack size */
+ p += 4;
+ rar->packed_size = archive_le64dec(&packed_size);
+ rar->unp_size = archive_le64dec(&unp_size);
+ }
+ else
+ {
+ rar->packed_size = archive_le32dec(file_header.pack_size);
+ rar->unp_size = archive_le32dec(file_header.unp_size);
+ }
+
+ /* TODO: Need to use CRC check for these kind of cases.
+ * For now, check if sizes are not < 0.
+ */
+ if (rar->packed_size < 0 || rar->unp_size < 0)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid sizes specified.");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* TODO: RARv3 subblocks contain comments. For now the complete block is
+ * consumed at the end.
+ */
+ if (head_type == NEWSUB_HEAD) {
+ size_t distance = p - (const char *)h;
+ header_size += rar->packed_size;
+ /* Make sure we have the extended data. */
+ if ((h = __archive_read_ahead(a, header_size - 7, NULL)) == NULL)
+ return (ARCHIVE_FATAL);
+ p = h;
+ endp = p + header_size - 7;
+ p += distance;
+ }
+
+ filename_size = archive_le16dec(file_header.name_size);
+ if (p + filename_size > endp) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid filename size");
+ return (ARCHIVE_FATAL);
+ }
+ if (rar->filename_allocated < filename_size+2) {
+ rar->filename = realloc(rar->filename, filename_size+2);
+ if (rar->filename == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Couldn't allocate memory.");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ filename = rar->filename;
+ memcpy(filename, p, filename_size);
+ filename[filename_size] = '\0';
+ if (rar->file_flags & FHD_UNICODE)
+ {
+ if (filename_size != strlen(filename))
+ {
+ unsigned char highbyte, flagbits, flagbyte, length, offset;
+
+ end = filename_size;
+ filename_size = 0;
+ offset = strlen(filename) + 1;
+ highbyte = *(p + offset++);
+ flagbits = 0;
+ flagbyte = 0;
+ while (offset < end && filename_size < end)
+ {
+ if (!flagbits)
+ {
+ flagbyte = *(p + offset++);
+ flagbits = 8;
+ }
+
+ flagbits -= 2;
+ switch((flagbyte >> flagbits) & 3)
+ {
+ case 0:
+ filename[filename_size++] = '\0';
+ filename[filename_size++] = *(p + offset++);
+ break;
+ case 1:
+ filename[filename_size++] = highbyte;
+ filename[filename_size++] = *(p + offset++);
+ break;
+ case 2:
+ filename[filename_size++] = *(p + offset + 1);
+ filename[filename_size++] = *(p + offset);
+ offset += 2;
+ break;
+ case 3:
+ {
+ length = *(p + offset++);
+ while (length)
+ {
+ if (filename_size >= end)
+ break;
+ filename[filename_size++] = *(p + offset);
+ length--;
+ }
+ }
+ break;
+ }
+ }
+ if (filename_size >= end) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid filename");
+ return (ARCHIVE_FATAL);
+ }
+ filename[filename_size++] = '\0';
+ filename[filename_size++] = '\0';
+
+ /* Decoded unicode form is UTF-16BE, so we have to update a string
+ * conversion object for it. */
+ if (rar->sconv_utf16be == NULL) {
+ rar->sconv_utf16be = archive_string_conversion_from_charset(
+ &a->archive, "UTF-16BE", 1);
+ if (rar->sconv_utf16be == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ fn_sconv = rar->sconv_utf16be;
+
+ strp = filename;
+ while (memcmp(strp, "\x00\x00", 2))
+ {
+ if (!memcmp(strp, "\x00\\", 2))
+ *(strp + 1) = '/';
+ strp += 2;
+ }
+ p += offset;
+ } else {
+ /*
+ * If FHD_UNICODE is set but no unicode data, this file name form
+ * is UTF-8, so we have to update a string conversion object for
+ * it accordingly.
+ */
+ if (rar->sconv_utf8 == NULL) {
+ rar->sconv_utf8 = archive_string_conversion_from_charset(
+ &a->archive, "UTF-8", 1);
+ if (rar->sconv_utf8 == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ fn_sconv = rar->sconv_utf8;
+ while ((strp = strchr(filename, '\\')) != NULL)
+ *strp = '/';
+ p += filename_size;
+ }
+ }
+ else
+ {
+ fn_sconv = sconv;
+ while ((strp = strchr(filename, '\\')) != NULL)
+ *strp = '/';
+ p += filename_size;
+ }
+
+ if (rar->file_flags & FHD_SALT)
+ {
+ if (p + 8 > endp) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid header size");
+ return (ARCHIVE_FATAL);
+ }
+ memcpy(rar->salt, p, 8);
+ p += 8;
+ }
+
+ if (rar->file_flags & FHD_EXTTIME) {
+ if (read_exttime(p, rar, endp) < 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid header size");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ __archive_read_consume(a, header_size - 7);
+
+ switch(file_header.host_os)
+ {
+ case OS_MSDOS:
+ case OS_OS2:
+ case OS_WIN32:
+ rar->mode = archive_le32dec(file_header.file_attr);
+ if (rar->mode & FILE_ATTRIBUTE_DIRECTORY)
+ rar->mode = AE_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ else
+ rar->mode = AE_IFREG;
+ rar->mode |= S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ break;
+
+ case OS_UNIX:
+ case OS_MAC_OS:
+ case OS_BEOS:
+ rar->mode = archive_le32dec(file_header.file_attr);
+ break;
+
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unknown file attributes from RAR file's host OS");
+ return (ARCHIVE_FATAL);
+ }
+
+ rar->bytes_remaining = rar->packed_size;
+ rar->bytes_uncopied = rar->bytes_unconsumed = 0;
+ rar->lzss.position = rar->dictionary_size = rar->offset = 0;
+ rar->offset_outgoing = 0;
+ rar->br.cache_avail = 0;
+ rar->br.avail_in = 0;
+ rar->crc_calculated = 0;
+ rar->entry_eof = 0;
+ rar->valid = 1;
+ rar->is_ppmd_block = 0;
+ rar->start_new_table = 1;
+ free(rar->unp_buffer);
+ rar->unp_buffer = NULL;
+ rar->unp_offset = 0;
+ rar->unp_buffer_size = UNP_BUFFER_SIZE;
+ memset(rar->lengthtable, 0, sizeof(rar->lengthtable));
+ __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
+ rar->ppmd_valid = rar->ppmd_eod = 0;
+
+ /* Don't set any archive entries for non-file header types */
+ if (head_type == NEWSUB_HEAD)
+ return ret;
+
+ archive_entry_set_mtime(entry, rar->mtime, rar->mnsec);
+ archive_entry_set_ctime(entry, rar->ctime, rar->cnsec);
+ archive_entry_set_atime(entry, rar->atime, rar->ansec);
+ archive_entry_set_size(entry, rar->unp_size);
+ archive_entry_set_mode(entry, rar->mode);
+
+ if (archive_entry_copy_pathname_l(entry, filename, filename_size, fn_sconv))
+ {
+ if (errno == ENOMEM)
+ {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for Pathname");
+ return (ARCHIVE_FATAL);
+ }
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Pathname cannot be converted from %s to current locale.",
+ archive_string_conversion_charset_name(fn_sconv));
+ ret = (ARCHIVE_WARN);
+ }
+
+ if (((rar->mode) & AE_IFMT) == AE_IFLNK)
+ {
+ /* Make sure a symbolic-link file does not have its body. */
+ rar->bytes_remaining = 0;
+ archive_entry_set_size(entry, 0);
+
+ /* Read a symbolic-link name. */
+ if ((ret2 = read_symlink_stored(a, entry, sconv)) < (ARCHIVE_WARN))
+ return ret2;
+ if (ret > ret2)
+ ret = ret2;
+ }
+
+ if (rar->bytes_remaining == 0)
+ rar->entry_eof = 1;
+
+ return ret;
+}
+
+static time_t
+get_time(int ttime)
+{
+ struct tm tm;
+ tm.tm_sec = 2 * (ttime & 0x1f);
+ tm.tm_min = (ttime >> 5) & 0x3f;
+ tm.tm_hour = (ttime >> 11) & 0x1f;
+ tm.tm_mday = (ttime >> 16) & 0x1f;
+ tm.tm_mon = ((ttime >> 21) & 0x0f) - 1;
+ tm.tm_year = ((ttime >> 25) & 0x7f) + 80;
+ tm.tm_isdst = -1;
+ return mktime(&tm);
+}
+
+static int
+read_exttime(const char *p, struct rar *rar, const char *endp)
+{
+ unsigned rmode, flags, rem, j, count;
+ int ttime, i;
+ struct tm *tm;
+ time_t t;
+ long nsec;
+
+ if (p + 2 > endp)
+ return (-1);
+ flags = archive_le16dec(p);
+ p += 2;
+
+ for (i = 3; i >= 0; i--)
+ {
+ t = 0;
+ if (i == 3)
+ t = rar->mtime;
+ rmode = flags >> i * 4;
+ if (rmode & 8)
+ {
+ if (!t)
+ {
+ if (p + 4 > endp)
+ return (-1);
+ ttime = archive_le32dec(p);
+ t = get_time(ttime);
+ p += 4;
+ }
+ rem = 0;
+ count = rmode & 3;
+ if (p + count > endp)
+ return (-1);
+ for (j = 0; j < count; j++)
+ {
+ rem = ((*p) << 16) | (rem >> 8);
+ p++;
+ }
+ tm = localtime(&t);
+ nsec = tm->tm_sec + rem / NS_UNIT;
+ if (rmode & 4)
+ {
+ tm->tm_sec++;
+ t = mktime(tm);
+ }
+ if (i == 3)
+ {
+ rar->mtime = t;
+ rar->mnsec = nsec;
+ }
+ else if (i == 2)
+ {
+ rar->ctime = t;
+ rar->cnsec = nsec;
+ }
+ else if (i == 1)
+ {
+ rar->atime = t;
+ rar->ansec = nsec;
+ }
+ else
+ {
+ rar->arctime = t;
+ rar->arcnsec = nsec;
+ }
+ }
+ }
+ return (0);
+}
+
+static int
+read_symlink_stored(struct archive_read *a, struct archive_entry *entry,
+ struct archive_string_conv *sconv)
+{
+ const void *h;
+ const char *p;
+ struct rar *rar;
+ int ret = (ARCHIVE_OK);
+
+ rar = (struct rar *)(a->format->data);
+ if ((h = __archive_read_ahead(a, rar->packed_size, NULL)) == NULL)
+ return (ARCHIVE_FATAL);
+ p = h;
+
+ if (archive_entry_copy_symlink_l(entry, p, rar->packed_size, sconv))
+ {
+ if (errno == ENOMEM)
+ {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for link");
+ return (ARCHIVE_FATAL);
+ }
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "link cannot be converted from %s to current locale.",
+ archive_string_conversion_charset_name(sconv));
+ ret = (ARCHIVE_WARN);
+ }
+ __archive_read_consume(a, rar->packed_size);
+ return ret;
+}
+
+static int
+read_data_stored(struct archive_read *a, const void **buff, size_t *size,
+ int64_t *offset)
+{
+ struct rar *rar;
+ ssize_t bytes_avail;
+
+ rar = (struct rar *)(a->format->data);
+ if (rar->bytes_remaining == 0)
+ {
+ *buff = NULL;
+ *size = 0;
+ *offset = rar->offset;
+ if (rar->file_crc != rar->crc_calculated) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "File CRC error");
+ return (ARCHIVE_FATAL);
+ }
+ rar->entry_eof = 1;
+ return (ARCHIVE_EOF);
+ }
+
+ *buff = __archive_read_ahead(a, 1, &bytes_avail);
+ if (bytes_avail <= 0)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated RAR file data");
+ return (ARCHIVE_FATAL);
+ }
+ if (bytes_avail > rar->bytes_remaining)
+ bytes_avail = rar->bytes_remaining;
+
+ *size = bytes_avail;
+ *offset = rar->offset;
+ rar->offset += bytes_avail;
+ rar->bytes_remaining -= bytes_avail;
+ rar->bytes_unconsumed = bytes_avail;
+ /* Calculate File CRC. */
+ rar->crc_calculated = crc32(rar->crc_calculated, *buff, bytes_avail);
+ return (ARCHIVE_OK);
+}
+
+static int
+read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
+ int64_t *offset)
+{
+ struct rar *rar;
+ int64_t start, end, actualend;
+ size_t bs;
+ int ret = (ARCHIVE_OK), sym, code, lzss_offset, length, i;
+
+ rar = (struct rar *)(a->format->data);
+
+ do {
+ if (!rar->valid)
+ return (ARCHIVE_FATAL);
+ if (rar->ppmd_eod ||
+ (rar->dictionary_size && rar->offset >= rar->unp_size))
+ {
+ if (rar->unp_offset > 0) {
+ /*
+ * We have unprocessed extracted data. write it out.
+ */
+ *buff = rar->unp_buffer;
+ *size = rar->unp_offset;
+ *offset = rar->offset_outgoing;
+ rar->offset_outgoing += *size;
+ /* Calculate File CRC. */
+ rar->crc_calculated = crc32(rar->crc_calculated, *buff, *size);
+ rar->unp_offset = 0;
+ return (ARCHIVE_OK);
+ }
+ *buff = NULL;
+ *size = 0;
+ *offset = rar->offset;
+ if (rar->file_crc != rar->crc_calculated) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "File CRC error");
+ return (ARCHIVE_FATAL);
+ }
+ rar->entry_eof = 1;
+ return (ARCHIVE_EOF);
+ }
+
+ if (!rar->is_ppmd_block && rar->dictionary_size && rar->bytes_uncopied > 0)
+ {
+ if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
+ bs = rar->unp_buffer_size - rar->unp_offset;
+ else
+ bs = rar->bytes_uncopied;
+ ret = copy_from_lzss_window(a, buff, rar->offset, bs);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ rar->offset += bs;
+ rar->bytes_uncopied -= bs;
+ if (*buff != NULL) {
+ rar->unp_offset = 0;
+ *size = rar->unp_buffer_size;
+ *offset = rar->offset_outgoing;
+ rar->offset_outgoing += *size;
+ /* Calculate File CRC. */
+ rar->crc_calculated = crc32(rar->crc_calculated, *buff, *size);
+ return (ret);
+ }
+ continue;
+ }
+
+ if (!rar->br.next_in &&
+ (ret = rar_br_preparation(a, &(rar->br))) < ARCHIVE_WARN)
+ return (ret);
+ if (rar->start_new_table && ((ret = parse_codes(a)) < (ARCHIVE_WARN)))
+ return (ret);
+
+ if (rar->is_ppmd_block)
+ {
+ if ((sym = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
+ &rar->ppmd7_context, &rar->range_dec.p)) < 0)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid symbol");
+ return (ARCHIVE_FATAL);
+ }
+ if(sym != rar->ppmd_escape)
+ {
+ lzss_emit_literal(rar, sym);
+ rar->bytes_uncopied++;
+ }
+ else
+ {
+ if ((code = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
+ &rar->ppmd7_context, &rar->range_dec.p)) < 0)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid symbol");
+ return (ARCHIVE_FATAL);
+ }
+
+ switch(code)
+ {
+ case 0:
+ rar->start_new_table = 1;
+ return read_data_compressed(a, buff, size, offset);
+
+ case 2:
+ rar->ppmd_eod = 1;/* End Of ppmd Data. */
+ continue;
+
+ case 3:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Parsing filters is unsupported.");
+ return (ARCHIVE_FAILED);
+
+ case 4:
+ lzss_offset = 0;
+ for (i = 2; i >= 0; i--)
+ {
+ if ((code = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
+ &rar->ppmd7_context, &rar->range_dec.p)) < 0)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid symbol");
+ return (ARCHIVE_FATAL);
+ }
+ lzss_offset |= code << (i * 8);
+ }
+ if ((length = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
+ &rar->ppmd7_context, &rar->range_dec.p)) < 0)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid symbol");
+ return (ARCHIVE_FATAL);
+ }
+ lzss_emit_match(rar, lzss_offset + 2, length + 32);
+ rar->bytes_uncopied += length + 32;
+ break;
+
+ case 5:
+ if ((length = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
+ &rar->ppmd7_context, &rar->range_dec.p)) < 0)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid symbol");
+ return (ARCHIVE_FATAL);
+ }
+ lzss_emit_match(rar, 1, length + 4);
+ rar->bytes_uncopied += length + 4;
+ break;
+
+ default:
+ lzss_emit_literal(rar, sym);
+ rar->bytes_uncopied++;
+ }
+ }
+ }
+ else
+ {
+ start = rar->offset;
+ end = start + rar->dictionary_size;
+ rar->filterstart = INT64_MAX;
+
+ if ((actualend = expand(a, end)) < 0)
+ return ((int)actualend);
+
+ rar->bytes_uncopied = actualend - start;
+ if (rar->bytes_uncopied == 0) {
+ /* Broken RAR files cause this case.
+ * NOTE: If this case were possible on a normal RAR file
+ * we would find out where it was actually bad and
+ * what we would do to solve it. */
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Internal error extracting RAR file");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
+ bs = rar->unp_buffer_size - rar->unp_offset;
+ else
+ bs = rar->bytes_uncopied;
+ ret = copy_from_lzss_window(a, buff, rar->offset, bs);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ rar->offset += bs;
+ rar->bytes_uncopied -= bs;
+ /*
+ * If *buff is NULL, it means unp_buffer is not full.
+ * So we have to continue extracting a RAR file.
+ */
+ } while (*buff == NULL);
+
+ rar->unp_offset = 0;
+ *size = rar->unp_buffer_size;
+ *offset = rar->offset_outgoing;
+ rar->offset_outgoing += *size;
+ /* Calculate File CRC. */
+ rar->crc_calculated = crc32(rar->crc_calculated, *buff, *size);
+ return ret;
+}
+
+static int
+parse_codes(struct archive_read *a)
+{
+ int i, j, val, n, r;
+ unsigned char bitlengths[MAX_SYMBOLS], zerocount, ppmd_flags;
+ unsigned int maxorder;
+ struct huffman_code precode;
+ struct rar *rar = (struct rar *)(a->format->data);
+ struct rar_br *br = &(rar->br);
+
+ free_codes(a);
+
+ /* Skip to the next byte */
+ rar_br_consume_unalined_bits(br);
+
+ /* PPMd block flag */
+ if (!rar_br_read_ahead(a, br, 1))
+ goto truncated_data;
+ if ((rar->is_ppmd_block = rar_br_bits(br, 1)) != 0)
+ {
+ rar_br_consume(br, 1);
+ if (!rar_br_read_ahead(a, br, 7))
+ goto truncated_data;
+ ppmd_flags = rar_br_bits(br, 7);
+ rar_br_consume(br, 7);
+
+ /* Memory is allocated in MB */
+ if (ppmd_flags & 0x20)
+ {
+ if (!rar_br_read_ahead(a, br, 8))
+ goto truncated_data;
+ rar->dictionary_size = (rar_br_bits(br, 8) + 1) << 20;
+ rar_br_consume(br, 8);
+ }
+
+ if (ppmd_flags & 0x40)
+ {
+ if (!rar_br_read_ahead(a, br, 8))
+ goto truncated_data;
+ rar->ppmd_escape = rar->ppmd7_context.InitEsc = rar_br_bits(br, 8);
+ rar_br_consume(br, 8);
+ }
+ else
+ rar->ppmd_escape = 2;
+
+ if (ppmd_flags & 0x20)
+ {
+ maxorder = (ppmd_flags & 0x1F) + 1;
+ if(maxorder > 16)
+ maxorder = 16 + (maxorder - 16) * 3;
+
+ if (maxorder == 1)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated RAR file data");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Make sure ppmd7_contest is freed before Ppmd7_Construct
+ * because reading a broken file cause this abnormal sequence. */
+ __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
+
+ rar->bytein.a = a;
+ rar->bytein.Read = &ppmd_read;
+ __archive_ppmd7_functions.PpmdRAR_RangeDec_CreateVTable(&rar->range_dec);
+ rar->range_dec.Stream = &rar->bytein;
+ __archive_ppmd7_functions.Ppmd7_Construct(&rar->ppmd7_context);
+
+ if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
+ rar->dictionary_size, &g_szalloc))
+ {
+ archive_set_error(&a->archive, ENOMEM,
+ "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ if (!__archive_ppmd7_functions.PpmdRAR_RangeDec_Init(&rar->range_dec))
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unable to initialize PPMd range decoder");
+ return (ARCHIVE_FATAL);
+ }
+ __archive_ppmd7_functions.Ppmd7_Init(&rar->ppmd7_context, maxorder);
+ rar->ppmd_valid = 1;
+ }
+ else
+ {
+ if (!rar->ppmd_valid) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid PPMd sequence");
+ return (ARCHIVE_FATAL);
+ }
+ if (!__archive_ppmd7_functions.PpmdRAR_RangeDec_Init(&rar->range_dec))
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unable to initialize PPMd range decoder");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ }
+ else
+ {
+ rar_br_consume(br, 1);
+
+ /* Keep existing table flag */
+ if (!rar_br_read_ahead(a, br, 1))
+ goto truncated_data;
+ if (!rar_br_bits(br, 1))
+ memset(rar->lengthtable, 0, sizeof(rar->lengthtable));
+ rar_br_consume(br, 1);
+
+ memset(&bitlengths, 0, sizeof(bitlengths));
+ for (i = 0; i < MAX_SYMBOLS;)
+ {
+ if (!rar_br_read_ahead(a, br, 4))
+ goto truncated_data;
+ bitlengths[i++] = rar_br_bits(br, 4);
+ rar_br_consume(br, 4);
+ if (bitlengths[i-1] == 0xF)
+ {
+ if (!rar_br_read_ahead(a, br, 4))
+ goto truncated_data;
+ zerocount = rar_br_bits(br, 4);
+ rar_br_consume(br, 4);
+ if (zerocount)
+ {
+ i--;
+ for (j = 0; j < zerocount + 2 && i < MAX_SYMBOLS; j++)
+ bitlengths[i++] = 0;
+ }
+ }
+ }
+
+ memset(&precode, 0, sizeof(precode));
+ r = create_code(a, &precode, bitlengths, MAX_SYMBOLS, MAX_SYMBOL_LENGTH);
+ if (r != ARCHIVE_OK) {
+ free(precode.tree);
+ free(precode.table);
+ return (r);
+ }
+
+ for (i = 0; i < HUFFMAN_TABLE_SIZE;)
+ {
+ if ((val = read_next_symbol(a, &precode)) < 0) {
+ free(precode.tree);
+ free(precode.table);
+ return (ARCHIVE_FATAL);
+ }
+ if (val < 16)
+ {
+ rar->lengthtable[i] = (rar->lengthtable[i] + val) & 0xF;
+ i++;
+ }
+ else if (val < 18)
+ {
+ if (i == 0)
+ {
+ free(precode.tree);
+ free(precode.table);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Internal error extracting RAR file.");
+ return (ARCHIVE_FATAL);
+ }
+
+ if(val == 16) {
+ if (!rar_br_read_ahead(a, br, 3)) {
+ free(precode.tree);
+ free(precode.table);
+ goto truncated_data;
+ }
+ n = rar_br_bits(br, 3) + 3;
+ rar_br_consume(br, 3);
+ } else {
+ if (!rar_br_read_ahead(a, br, 7)) {
+ free(precode.tree);
+ free(precode.table);
+ goto truncated_data;
+ }
+ n = rar_br_bits(br, 7) + 11;
+ rar_br_consume(br, 7);
+ }
+
+ for (j = 0; j < n && i < HUFFMAN_TABLE_SIZE; j++)
+ {
+ rar->lengthtable[i] = rar->lengthtable[i-1];
+ i++;
+ }
+ }
+ else
+ {
+ if(val == 18) {
+ if (!rar_br_read_ahead(a, br, 3)) {
+ free(precode.tree);
+ free(precode.table);
+ goto truncated_data;
+ }
+ n = rar_br_bits(br, 3) + 3;
+ rar_br_consume(br, 3);
+ } else {
+ if (!rar_br_read_ahead(a, br, 7)) {
+ free(precode.tree);
+ free(precode.table);
+ goto truncated_data;
+ }
+ n = rar_br_bits(br, 7) + 11;
+ rar_br_consume(br, 7);
+ }
+
+ for(j = 0; j < n && i < HUFFMAN_TABLE_SIZE; j++)
+ rar->lengthtable[i++] = 0;
+ }
+ }
+ free(precode.tree);
+ free(precode.table);
+
+ r = create_code(a, &rar->maincode, &rar->lengthtable[0], MAINCODE_SIZE,
+ MAX_SYMBOL_LENGTH);
+ if (r != ARCHIVE_OK)
+ return (r);
+ r = create_code(a, &rar->offsetcode, &rar->lengthtable[MAINCODE_SIZE],
+ OFFSETCODE_SIZE, MAX_SYMBOL_LENGTH);
+ if (r != ARCHIVE_OK)
+ return (r);
+ r = create_code(a, &rar->lowoffsetcode,
+ &rar->lengthtable[MAINCODE_SIZE + OFFSETCODE_SIZE],
+ LOWOFFSETCODE_SIZE, MAX_SYMBOL_LENGTH);
+ if (r != ARCHIVE_OK)
+ return (r);
+ r = create_code(a, &rar->lengthcode,
+ &rar->lengthtable[MAINCODE_SIZE + OFFSETCODE_SIZE +
+ LOWOFFSETCODE_SIZE], LENGTHCODE_SIZE, MAX_SYMBOL_LENGTH);
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
+
+ if (!rar->dictionary_size || !rar->lzss.window)
+ {
+ /* Seems as though dictionary sizes are not used. Even so, minimize
+ * memory usage as much as possible.
+ */
+ if (rar->unp_size >= DICTIONARY_MAX_SIZE)
+ rar->dictionary_size = DICTIONARY_MAX_SIZE;
+ else
+ rar->dictionary_size = rar_fls(rar->unp_size) << 1;
+ rar->lzss.window = (unsigned char *)realloc(rar->lzss.window,
+ rar->dictionary_size);
+ if (rar->lzss.window == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Unable to allocate memory for uncompressed data.");
+ return (ARCHIVE_FATAL);
+ }
+ memset(rar->lzss.window, 0, rar->dictionary_size);
+ rar->lzss.mask = rar->dictionary_size - 1;
+ }
+
+ rar->start_new_table = 0;
+ return (ARCHIVE_OK);
+truncated_data:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated RAR file data");
+ rar->valid = 0;
+ return (ARCHIVE_FATAL);
+}
+
+static void
+free_codes(struct archive_read *a)
+{
+ struct rar *rar = (struct rar *)(a->format->data);
+ free(rar->maincode.tree);
+ free(rar->offsetcode.tree);
+ free(rar->lowoffsetcode.tree);
+ free(rar->lengthcode.tree);
+ free(rar->maincode.table);
+ free(rar->offsetcode.table);
+ free(rar->lowoffsetcode.table);
+ free(rar->lengthcode.table);
+ memset(&rar->maincode, 0, sizeof(rar->maincode));
+ memset(&rar->offsetcode, 0, sizeof(rar->offsetcode));
+ memset(&rar->lowoffsetcode, 0, sizeof(rar->lowoffsetcode));
+ memset(&rar->lengthcode, 0, sizeof(rar->lengthcode));
+}
+
+
+static int
+read_next_symbol(struct archive_read *a, struct huffman_code *code)
+{
+ unsigned char bit;
+ unsigned int bits;
+ int length, value, node;
+ struct rar *rar;
+ struct rar_br *br;
+
+ if (!code->table)
+ {
+ if (make_table(a, code) != (ARCHIVE_OK))
+ return -1;
+ }
+
+ rar = (struct rar *)(a->format->data);
+ br = &(rar->br);
+
+ /* Look ahead (peek) at bits */
+ if (!rar_br_read_ahead(a, br, code->tablesize)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated RAR file data");
+ rar->valid = 0;
+ return -1;
+ }
+ bits = rar_br_bits(br, code->tablesize);
+
+ length = code->table[bits].length;
+ value = code->table[bits].value;
+
+ if (length < 0)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid prefix code in bitstream");
+ return -1;
+ }
+
+ if (length <= code->tablesize)
+ {
+ /* Skip length bits */
+ rar_br_consume(br, length);
+ return value;
+ }
+
+ /* Skip tablesize bits */
+ rar_br_consume(br, code->tablesize);
+
+ node = value;
+ while (!(code->tree[node].branches[0] ==
+ code->tree[node].branches[1]))
+ {
+ if (!rar_br_read_ahead(a, br, 1)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated RAR file data");
+ rar->valid = 0;
+ return -1;
+ }
+ bit = rar_br_bits(br, 1);
+ rar_br_consume(br, 1);
+
+ if (code->tree[node].branches[bit] < 0)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid prefix code in bitstream");
+ return -1;
+ }
+ node = code->tree[node].branches[bit];
+ }
+
+ return code->tree[node].branches[0];
+}
+
+static int
+create_code(struct archive_read *a, struct huffman_code *code,
+ unsigned char *lengths, int numsymbols, char maxlength)
+{
+ int i, j, codebits = 0, symbolsleft = numsymbols;
+
+ if (new_node(code) < 0) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Unable to allocate memory for node data.");
+ return (ARCHIVE_FATAL);
+ }
+ code->numentries = 1;
+ code->minlength = INT_MAX;
+ code->maxlength = INT_MIN;
+ codebits = 0;
+ for(i = 1; i <= maxlength; i++)
+ {
+ for(j = 0; j < numsymbols; j++)
+ {
+ if (lengths[j] != i) continue;
+ if (add_value(a, code, j, codebits, i) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ codebits++;
+ if (--symbolsleft <= 0) { break; break; }
+ }
+ codebits <<= 1;
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+add_value(struct archive_read *a, struct huffman_code *code, int value,
+ int codebits, int length)
+{
+ int repeatpos, lastnode, bitpos, bit, repeatnode, nextnode;
+
+ free(code->table);
+ code->table = NULL;
+
+ if(length > code->maxlength)
+ code->maxlength = length;
+ if(length < code->minlength)
+ code->minlength = length;
+
+ repeatpos = -1;
+ if (repeatpos == 0 || (repeatpos >= 0
+ && (((codebits >> (repeatpos - 1)) & 3) == 0
+ || ((codebits >> (repeatpos - 1)) & 3) == 3)))
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid repeat position");
+ return (ARCHIVE_FATAL);
+ }
+
+ lastnode = 0;
+ for (bitpos = length - 1; bitpos >= 0; bitpos--)
+ {
+ bit = (codebits >> bitpos) & 1;
+
+ /* Leaf node check */
+ if (code->tree[lastnode].branches[0] ==
+ code->tree[lastnode].branches[1])
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Prefix found");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (bitpos == repeatpos)
+ {
+ /* Open branch check */
+ if (!(code->tree[lastnode].branches[bit] < 0))
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid repeating code");
+ return (ARCHIVE_FATAL);
+ }
+
+ if ((repeatnode = new_node(code)) < 0) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Unable to allocate memory for node data.");
+ return (ARCHIVE_FATAL);
+ }
+ if ((nextnode = new_node(code)) < 0) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Unable to allocate memory for node data.");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Set branches */
+ code->tree[lastnode].branches[bit] = repeatnode;
+ code->tree[repeatnode].branches[bit] = repeatnode;
+ code->tree[repeatnode].branches[bit^1] = nextnode;
+ lastnode = nextnode;
+
+ bitpos++; /* terminating bit already handled, skip it */
+ }
+ else
+ {
+ /* Open branch check */
+ if (code->tree[lastnode].branches[bit] < 0)
+ {
+ if (new_node(code) < 0) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Unable to allocate memory for node data.");
+ return (ARCHIVE_FATAL);
+ }
+ code->tree[lastnode].branches[bit] = code->numentries++;
+ }
+
+ /* set to branch */
+ lastnode = code->tree[lastnode].branches[bit];
+ }
+ }
+
+ if (!(code->tree[lastnode].branches[0] == -1
+ && code->tree[lastnode].branches[1] == -2))
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Prefix found");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Set leaf value */
+ code->tree[lastnode].branches[0] = value;
+ code->tree[lastnode].branches[1] = value;
+
+ return (ARCHIVE_OK);
+}
+
+static int
+new_node(struct huffman_code *code)
+{
+ code->tree = (struct huffman_tree_node *)realloc(code->tree,
+ (code->numentries + 1) * sizeof(*code->tree));
+ if (code->tree == NULL)
+ return (-1);
+ code->tree[code->numentries].branches[0] = -1;
+ code->tree[code->numentries].branches[1] = -2;
+ return 1;
+}
+
+static int
+make_table(struct archive_read *a, struct huffman_code *code)
+{
+ if (code->maxlength < code->minlength || code->maxlength > 10)
+ code->tablesize = 10;
+ else
+ code->tablesize = code->maxlength;
+
+ code->table =
+ (struct huffman_table_entry *)malloc(sizeof(*code->table)
+ * (1 << code->tablesize));
+
+ return make_table_recurse(a, code, 0, code->table, 0, code->tablesize);
+}
+
+static int
+make_table_recurse(struct archive_read *a, struct huffman_code *code, int node,
+ struct huffman_table_entry *table, int depth,
+ int maxdepth)
+{
+ int currtablesize, i, ret = (ARCHIVE_OK);
+
+ if (!code->tree)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Huffman tree was not created.");
+ return (ARCHIVE_FATAL);
+ }
+ if (node < 0 || node >= code->numentries)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid location to Huffman tree specified.");
+ return (ARCHIVE_FATAL);
+ }
+
+ currtablesize = 1 << (maxdepth - depth);
+
+ if (code->tree[node].branches[0] ==
+ code->tree[node].branches[1])
+ {
+ for(i = 0; i < currtablesize; i++)
+ {
+ table[i].length = depth;
+ table[i].value = code->tree[node].branches[0];
+ }
+ }
+ else if (node < 0)
+ {
+ for(i = 0; i < currtablesize; i++)
+ table[i].length = -1;
+ }
+ else
+ {
+ if(depth == maxdepth)
+ {
+ table[0].length = maxdepth + 1;
+ table[0].value = node;
+ }
+ else
+ {
+ ret |= make_table_recurse(a, code, code->tree[node].branches[0], table,
+ depth + 1, maxdepth);
+ ret |= make_table_recurse(a, code, code->tree[node].branches[1],
+ table + currtablesize / 2, depth + 1, maxdepth);
+ }
+ }
+ return ret;
+}
+
+static int64_t
+expand(struct archive_read *a, int64_t end)
+{
+ static const unsigned char lengthbases[] =
+ { 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 10, 12, 14, 16, 20,
+ 24, 28, 32, 40, 48, 56, 64,
+ 80, 96, 112, 128, 160, 192, 224 };
+ static const unsigned char lengthbits[] =
+ { 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 2, 2,
+ 2, 2, 3, 3, 3, 3, 4,
+ 4, 4, 4, 5, 5, 5, 5 };
+ static const unsigned int offsetbases[] =
+ { 0, 1, 2, 3, 4, 6,
+ 8, 12, 16, 24, 32, 48,
+ 64, 96, 128, 192, 256, 384,
+ 512, 768, 1024, 1536, 2048, 3072,
+ 4096, 6144, 8192, 12288, 16384, 24576,
+ 32768, 49152, 65536, 98304, 131072, 196608,
+ 262144, 327680, 393216, 458752, 524288, 589824,
+ 655360, 720896, 786432, 851968, 917504, 983040,
+ 1048576, 1310720, 1572864, 1835008, 2097152, 2359296,
+ 2621440, 2883584, 3145728, 3407872, 3670016, 3932160 };
+ static const unsigned char offsetbits[] =
+ { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
+ 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
+ 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 };
+ static const unsigned char shortbases[] =
+ { 0, 4, 8, 16, 32, 64, 128, 192 };
+ static const unsigned char shortbits[] =
+ { 2, 2, 3, 4, 5, 6, 6, 6 };
+
+ int symbol, offs, len, offsindex, lensymbol, i, offssymbol, lowoffsetsymbol;
+ unsigned char newfile;
+ struct rar *rar = (struct rar *)(a->format->data);
+ struct rar_br *br = &(rar->br);
+
+ if (rar->filterstart < end)
+ end = rar->filterstart;
+
+ while (1)
+ {
+ if (rar->output_last_match &&
+ lzss_position(&rar->lzss) + rar->lastlength <= end)
+ {
+ lzss_emit_match(rar, rar->lastoffset, rar->lastlength);
+ rar->output_last_match = 0;
+ }
+
+ if(rar->is_ppmd_block || rar->output_last_match ||
+ lzss_position(&rar->lzss) >= end)
+ return lzss_position(&rar->lzss);
+
+ if ((symbol = read_next_symbol(a, &rar->maincode)) < 0)
+ return (ARCHIVE_FATAL);
+ rar->output_last_match = 0;
+
+ if (symbol < 256)
+ {
+ lzss_emit_literal(rar, symbol);
+ continue;
+ }
+ else if (symbol == 256)
+ {
+ if (!rar_br_read_ahead(a, br, 1))
+ goto truncated_data;
+ newfile = !rar_br_bits(br, 1);
+ rar_br_consume(br, 1);
+
+ if(newfile)
+ {
+ rar->start_new_block = 1;
+ if (!rar_br_read_ahead(a, br, 1))
+ goto truncated_data;
+ rar->start_new_table = rar_br_bits(br, 1);
+ rar_br_consume(br, 1);
+ return lzss_position(&rar->lzss);
+ }
+ else
+ {
+ if (parse_codes(a) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ continue;
+ }
+ }
+ else if(symbol==257)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Parsing filters is unsupported.");
+ return (ARCHIVE_FAILED);
+ }
+ else if(symbol==258)
+ {
+ if(rar->lastlength == 0)
+ continue;
+
+ offs = rar->lastoffset;
+ len = rar->lastlength;
+ }
+ else if (symbol <= 262)
+ {
+ offsindex = symbol - 259;
+ offs = rar->oldoffset[offsindex];
+
+ if ((lensymbol = read_next_symbol(a, &rar->lengthcode)) < 0)
+ goto bad_data;
+ if (lensymbol > (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
+ goto bad_data;
+ if (lensymbol > (int)(sizeof(lengthbits)/sizeof(lengthbits[0])))
+ goto bad_data;
+ len = lengthbases[lensymbol] + 2;
+ if (lengthbits[lensymbol] > 0) {
+ if (!rar_br_read_ahead(a, br, lengthbits[lensymbol]))
+ goto truncated_data;
+ len += rar_br_bits(br, lengthbits[lensymbol]);
+ rar_br_consume(br, lengthbits[lensymbol]);
+ }
+
+ for (i = offsindex; i > 0; i--)
+ rar->oldoffset[i] = rar->oldoffset[i-1];
+ rar->oldoffset[0] = offs;
+ }
+ else if(symbol<=270)
+ {
+ offs = shortbases[symbol-263] + 1;
+ if(shortbits[symbol-263] > 0) {
+ if (!rar_br_read_ahead(a, br, shortbits[symbol-263]))
+ goto truncated_data;
+ offs += rar_br_bits(br, shortbits[symbol-263]);
+ rar_br_consume(br, shortbits[symbol-263]);
+ }
+
+ len = 2;
+
+ for(i = 3; i > 0; i--)
+ rar->oldoffset[i] = rar->oldoffset[i-1];
+ rar->oldoffset[0] = offs;
+ }
+ else
+ {
+ if (symbol-271 > (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
+ goto bad_data;
+ if (symbol-271 > (int)(sizeof(lengthbits)/sizeof(lengthbits[0])))
+ goto bad_data;
+ len = lengthbases[symbol-271]+3;
+ if(lengthbits[symbol-271] > 0) {
+ if (!rar_br_read_ahead(a, br, lengthbits[symbol-271]))
+ goto truncated_data;
+ len += rar_br_bits(br, lengthbits[symbol-271]);
+ rar_br_consume(br, lengthbits[symbol-271]);
+ }
+
+ if ((offssymbol = read_next_symbol(a, &rar->offsetcode)) < 0)
+ goto bad_data;
+ if (offssymbol > (int)(sizeof(offsetbases)/sizeof(offsetbases[0])))
+ goto bad_data;
+ if (offssymbol > (int)(sizeof(offsetbits)/sizeof(offsetbits[0])))
+ goto bad_data;
+ offs = offsetbases[offssymbol]+1;
+ if(offsetbits[offssymbol] > 0)
+ {
+ if(offssymbol > 9)
+ {
+ if(offsetbits[offssymbol] > 4) {
+ if (!rar_br_read_ahead(a, br, offsetbits[offssymbol] - 4))
+ goto truncated_data;
+ offs += rar_br_bits(br, offsetbits[offssymbol] - 4) << 4;
+ rar_br_consume(br, offsetbits[offssymbol] - 4);
+ }
+
+ if(rar->numlowoffsetrepeats > 0)
+ {
+ rar->numlowoffsetrepeats--;
+ offs += rar->lastlowoffset;
+ }
+ else
+ {
+ if ((lowoffsetsymbol =
+ read_next_symbol(a, &rar->lowoffsetcode)) < 0)
+ return (ARCHIVE_FATAL);
+ if(lowoffsetsymbol == 16)
+ {
+ rar->numlowoffsetrepeats = 15;
+ offs += rar->lastlowoffset;
+ }
+ else
+ {
+ offs += lowoffsetsymbol;
+ rar->lastlowoffset = lowoffsetsymbol;
+ }
+ }
+ }
+ else {
+ if (!rar_br_read_ahead(a, br, offsetbits[offssymbol]))
+ goto truncated_data;
+ offs += rar_br_bits(br, offsetbits[offssymbol]);
+ rar_br_consume(br, offsetbits[offssymbol]);
+ }
+ }
+
+ if (offs >= 0x40000)
+ len++;
+ if (offs >= 0x2000)
+ len++;
+
+ for(i = 3; i > 0; i--)
+ rar->oldoffset[i] = rar->oldoffset[i-1];
+ rar->oldoffset[0] = offs;
+ }
+
+ rar->lastoffset = offs;
+ rar->lastlength = len;
+ rar->output_last_match = 1;
+ }
+truncated_data:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated RAR file data");
+ rar->valid = 0;
+ return (ARCHIVE_FATAL);
+bad_data:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Bad RAR file data");
+ return (ARCHIVE_FATAL);
+}
+
+static int
+copy_from_lzss_window(struct archive_read *a, const void **buffer,
+ int64_t startpos, int length)
+{
+ int windowoffs, firstpart;
+ struct rar *rar = (struct rar *)(a->format->data);
+
+ if (!rar->unp_buffer)
+ {
+ if ((rar->unp_buffer = malloc(rar->unp_buffer_size)) == NULL)
+ {
+ archive_set_error(&a->archive, ENOMEM,
+ "Unable to allocate memory for uncompressed data.");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ windowoffs = lzss_offset_for_position(&rar->lzss, startpos);
+ if(windowoffs + length <= lzss_size(&rar->lzss))
+ memcpy(&rar->unp_buffer[rar->unp_offset], &rar->lzss.window[windowoffs],
+ length);
+ else
+ {
+ firstpart = lzss_size(&rar->lzss) - windowoffs;
+ if (firstpart < 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Bad RAR file data");
+ return (ARCHIVE_FATAL);
+ }
+ if (firstpart < length) {
+ memcpy(&rar->unp_buffer[rar->unp_offset],
+ &rar->lzss.window[windowoffs], firstpart);
+ memcpy(&rar->unp_buffer[rar->unp_offset + firstpart],
+ &rar->lzss.window[0], length - firstpart);
+ } else
+ memcpy(&rar->unp_buffer[rar->unp_offset],
+ &rar->lzss.window[windowoffs], length);
+ }
+ rar->unp_offset += length;
+ if (rar->unp_offset >= rar->unp_buffer_size)
+ *buffer = rar->unp_buffer;
+ else
+ *buffer = NULL;
+ return (ARCHIVE_OK);
+}
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_string_composition.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_string_composition.h Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,1351 @@
+/*-
+ * Copyright (c) 2011 libarchive Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+/*
+ * ATTENTION!
+ * This file is generated by build/utils/gen_archive_string_composition_h.sh
+ * from http://unicode.org/Public/UNIDATA/UnicodeData.txt
+ *
+ * See also http://unicode.org/report/tr15/
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_STRING_COMPOSITION_H_INCLUDED
+#define ARCHIVE_STRING_COMPOSITION_H_INCLUDED
+
+struct unicode_composition_table {
+ uint32_t cp1;
+ uint32_t cp2;
+ uint32_t nfc;
+};
+
+static const struct unicode_composition_table u_composition_table[] = {
+ { 0x0003C , 0x00338 , 0x0226E },
+ { 0x0003D , 0x00338 , 0x02260 },
+ { 0x0003E , 0x00338 , 0x0226F },
+ { 0x00041 , 0x00300 , 0x000C0 },
+ { 0x00041 , 0x00301 , 0x000C1 },
+ { 0x00041 , 0x00302 , 0x000C2 },
+ { 0x00041 , 0x00303 , 0x000C3 },
+ { 0x00041 , 0x00304 , 0x00100 },
+ { 0x00041 , 0x00306 , 0x00102 },
+ { 0x00041 , 0x00307 , 0x00226 },
+ { 0x00041 , 0x00308 , 0x000C4 },
+ { 0x00041 , 0x00309 , 0x01EA2 },
+ { 0x00041 , 0x0030A , 0x000C5 },
+ { 0x00041 , 0x0030C , 0x001CD },
+ { 0x00041 , 0x0030F , 0x00200 },
+ { 0x00041 , 0x00311 , 0x00202 },
+ { 0x00041 , 0x00323 , 0x01EA0 },
+ { 0x00041 , 0x00325 , 0x01E00 },
+ { 0x00041 , 0x00328 , 0x00104 },
+ { 0x00042 , 0x00307 , 0x01E02 },
+ { 0x00042 , 0x00323 , 0x01E04 },
+ { 0x00042 , 0x00331 , 0x01E06 },
+ { 0x00043 , 0x00301 , 0x00106 },
+ { 0x00043 , 0x00302 , 0x00108 },
+ { 0x00043 , 0x00307 , 0x0010A },
+ { 0x00043 , 0x0030C , 0x0010C },
+ { 0x00043 , 0x00327 , 0x000C7 },
+ { 0x00044 , 0x00307 , 0x01E0A },
+ { 0x00044 , 0x0030C , 0x0010E },
+ { 0x00044 , 0x00323 , 0x01E0C },
+ { 0x00044 , 0x00327 , 0x01E10 },
+ { 0x00044 , 0x0032D , 0x01E12 },
+ { 0x00044 , 0x00331 , 0x01E0E },
+ { 0x00045 , 0x00300 , 0x000C8 },
+ { 0x00045 , 0x00301 , 0x000C9 },
+ { 0x00045 , 0x00302 , 0x000CA },
+ { 0x00045 , 0x00303 , 0x01EBC },
+ { 0x00045 , 0x00304 , 0x00112 },
+ { 0x00045 , 0x00306 , 0x00114 },
+ { 0x00045 , 0x00307 , 0x00116 },
+ { 0x00045 , 0x00308 , 0x000CB },
+ { 0x00045 , 0x00309 , 0x01EBA },
+ { 0x00045 , 0x0030C , 0x0011A },
+ { 0x00045 , 0x0030F , 0x00204 },
+ { 0x00045 , 0x00311 , 0x00206 },
+ { 0x00045 , 0x00323 , 0x01EB8 },
+ { 0x00045 , 0x00327 , 0x00228 },
+ { 0x00045 , 0x00328 , 0x00118 },
+ { 0x00045 , 0x0032D , 0x01E18 },
+ { 0x00045 , 0x00330 , 0x01E1A },
+ { 0x00046 , 0x00307 , 0x01E1E },
+ { 0x00047 , 0x00301 , 0x001F4 },
+ { 0x00047 , 0x00302 , 0x0011C },
+ { 0x00047 , 0x00304 , 0x01E20 },
+ { 0x00047 , 0x00306 , 0x0011E },
+ { 0x00047 , 0x00307 , 0x00120 },
+ { 0x00047 , 0x0030C , 0x001E6 },
+ { 0x00047 , 0x00327 , 0x00122 },
+ { 0x00048 , 0x00302 , 0x00124 },
+ { 0x00048 , 0x00307 , 0x01E22 },
+ { 0x00048 , 0x00308 , 0x01E26 },
+ { 0x00048 , 0x0030C , 0x0021E },
+ { 0x00048 , 0x00323 , 0x01E24 },
+ { 0x00048 , 0x00327 , 0x01E28 },
+ { 0x00048 , 0x0032E , 0x01E2A },
+ { 0x00049 , 0x00300 , 0x000CC },
+ { 0x00049 , 0x00301 , 0x000CD },
+ { 0x00049 , 0x00302 , 0x000CE },
+ { 0x00049 , 0x00303 , 0x00128 },
+ { 0x00049 , 0x00304 , 0x0012A },
+ { 0x00049 , 0x00306 , 0x0012C },
+ { 0x00049 , 0x00307 , 0x00130 },
+ { 0x00049 , 0x00308 , 0x000CF },
+ { 0x00049 , 0x00309 , 0x01EC8 },
+ { 0x00049 , 0x0030C , 0x001CF },
+ { 0x00049 , 0x0030F , 0x00208 },
+ { 0x00049 , 0x00311 , 0x0020A },
+ { 0x00049 , 0x00323 , 0x01ECA },
+ { 0x00049 , 0x00328 , 0x0012E },
+ { 0x00049 , 0x00330 , 0x01E2C },
+ { 0x0004A , 0x00302 , 0x00134 },
+ { 0x0004B , 0x00301 , 0x01E30 },
+ { 0x0004B , 0x0030C , 0x001E8 },
+ { 0x0004B , 0x00323 , 0x01E32 },
+ { 0x0004B , 0x00327 , 0x00136 },
+ { 0x0004B , 0x00331 , 0x01E34 },
+ { 0x0004C , 0x00301 , 0x00139 },
+ { 0x0004C , 0x0030C , 0x0013D },
+ { 0x0004C , 0x00323 , 0x01E36 },
+ { 0x0004C , 0x00327 , 0x0013B },
+ { 0x0004C , 0x0032D , 0x01E3C },
+ { 0x0004C , 0x00331 , 0x01E3A },
+ { 0x0004D , 0x00301 , 0x01E3E },
+ { 0x0004D , 0x00307 , 0x01E40 },
+ { 0x0004D , 0x00323 , 0x01E42 },
+ { 0x0004E , 0x00300 , 0x001F8 },
+ { 0x0004E , 0x00301 , 0x00143 },
+ { 0x0004E , 0x00303 , 0x000D1 },
+ { 0x0004E , 0x00307 , 0x01E44 },
+ { 0x0004E , 0x0030C , 0x00147 },
+ { 0x0004E , 0x00323 , 0x01E46 },
+ { 0x0004E , 0x00327 , 0x00145 },
+ { 0x0004E , 0x0032D , 0x01E4A },
+ { 0x0004E , 0x00331 , 0x01E48 },
+ { 0x0004F , 0x00300 , 0x000D2 },
+ { 0x0004F , 0x00301 , 0x000D3 },
+ { 0x0004F , 0x00302 , 0x000D4 },
+ { 0x0004F , 0x00303 , 0x000D5 },
+ { 0x0004F , 0x00304 , 0x0014C },
+ { 0x0004F , 0x00306 , 0x0014E },
+ { 0x0004F , 0x00307 , 0x0022E },
+ { 0x0004F , 0x00308 , 0x000D6 },
+ { 0x0004F , 0x00309 , 0x01ECE },
+ { 0x0004F , 0x0030B , 0x00150 },
+ { 0x0004F , 0x0030C , 0x001D1 },
+ { 0x0004F , 0x0030F , 0x0020C },
+ { 0x0004F , 0x00311 , 0x0020E },
+ { 0x0004F , 0x0031B , 0x001A0 },
+ { 0x0004F , 0x00323 , 0x01ECC },
+ { 0x0004F , 0x00328 , 0x001EA },
+ { 0x00050 , 0x00301 , 0x01E54 },
+ { 0x00050 , 0x00307 , 0x01E56 },
+ { 0x00052 , 0x00301 , 0x00154 },
+ { 0x00052 , 0x00307 , 0x01E58 },
+ { 0x00052 , 0x0030C , 0x00158 },
+ { 0x00052 , 0x0030F , 0x00210 },
+ { 0x00052 , 0x00311 , 0x00212 },
+ { 0x00052 , 0x00323 , 0x01E5A },
+ { 0x00052 , 0x00327 , 0x00156 },
+ { 0x00052 , 0x00331 , 0x01E5E },
+ { 0x00053 , 0x00301 , 0x0015A },
+ { 0x00053 , 0x00302 , 0x0015C },
+ { 0x00053 , 0x00307 , 0x01E60 },
+ { 0x00053 , 0x0030C , 0x00160 },
+ { 0x00053 , 0x00323 , 0x01E62 },
+ { 0x00053 , 0x00326 , 0x00218 },
+ { 0x00053 , 0x00327 , 0x0015E },
+ { 0x00054 , 0x00307 , 0x01E6A },
+ { 0x00054 , 0x0030C , 0x00164 },
+ { 0x00054 , 0x00323 , 0x01E6C },
+ { 0x00054 , 0x00326 , 0x0021A },
+ { 0x00054 , 0x00327 , 0x00162 },
+ { 0x00054 , 0x0032D , 0x01E70 },
+ { 0x00054 , 0x00331 , 0x01E6E },
+ { 0x00055 , 0x00300 , 0x000D9 },
+ { 0x00055 , 0x00301 , 0x000DA },
+ { 0x00055 , 0x00302 , 0x000DB },
+ { 0x00055 , 0x00303 , 0x00168 },
+ { 0x00055 , 0x00304 , 0x0016A },
+ { 0x00055 , 0x00306 , 0x0016C },
+ { 0x00055 , 0x00308 , 0x000DC },
+ { 0x00055 , 0x00309 , 0x01EE6 },
+ { 0x00055 , 0x0030A , 0x0016E },
+ { 0x00055 , 0x0030B , 0x00170 },
+ { 0x00055 , 0x0030C , 0x001D3 },
+ { 0x00055 , 0x0030F , 0x00214 },
+ { 0x00055 , 0x00311 , 0x00216 },
+ { 0x00055 , 0x0031B , 0x001AF },
+ { 0x00055 , 0x00323 , 0x01EE4 },
+ { 0x00055 , 0x00324 , 0x01E72 },
+ { 0x00055 , 0x00328 , 0x00172 },
+ { 0x00055 , 0x0032D , 0x01E76 },
+ { 0x00055 , 0x00330 , 0x01E74 },
+ { 0x00056 , 0x00303 , 0x01E7C },
+ { 0x00056 , 0x00323 , 0x01E7E },
+ { 0x00057 , 0x00300 , 0x01E80 },
+ { 0x00057 , 0x00301 , 0x01E82 },
+ { 0x00057 , 0x00302 , 0x00174 },
+ { 0x00057 , 0x00307 , 0x01E86 },
+ { 0x00057 , 0x00308 , 0x01E84 },
+ { 0x00057 , 0x00323 , 0x01E88 },
+ { 0x00058 , 0x00307 , 0x01E8A },
+ { 0x00058 , 0x00308 , 0x01E8C },
+ { 0x00059 , 0x00300 , 0x01EF2 },
+ { 0x00059 , 0x00301 , 0x000DD },
+ { 0x00059 , 0x00302 , 0x00176 },
+ { 0x00059 , 0x00303 , 0x01EF8 },
+ { 0x00059 , 0x00304 , 0x00232 },
+ { 0x00059 , 0x00307 , 0x01E8E },
+ { 0x00059 , 0x00308 , 0x00178 },
+ { 0x00059 , 0x00309 , 0x01EF6 },
+ { 0x00059 , 0x00323 , 0x01EF4 },
+ { 0x0005A , 0x00301 , 0x00179 },
+ { 0x0005A , 0x00302 , 0x01E90 },
+ { 0x0005A , 0x00307 , 0x0017B },
+ { 0x0005A , 0x0030C , 0x0017D },
+ { 0x0005A , 0x00323 , 0x01E92 },
+ { 0x0005A , 0x00331 , 0x01E94 },
+ { 0x00061 , 0x00300 , 0x000E0 },
+ { 0x00061 , 0x00301 , 0x000E1 },
+ { 0x00061 , 0x00302 , 0x000E2 },
+ { 0x00061 , 0x00303 , 0x000E3 },
+ { 0x00061 , 0x00304 , 0x00101 },
+ { 0x00061 , 0x00306 , 0x00103 },
+ { 0x00061 , 0x00307 , 0x00227 },
+ { 0x00061 , 0x00308 , 0x000E4 },
+ { 0x00061 , 0x00309 , 0x01EA3 },
+ { 0x00061 , 0x0030A , 0x000E5 },
+ { 0x00061 , 0x0030C , 0x001CE },
+ { 0x00061 , 0x0030F , 0x00201 },
+ { 0x00061 , 0x00311 , 0x00203 },
+ { 0x00061 , 0x00323 , 0x01EA1 },
+ { 0x00061 , 0x00325 , 0x01E01 },
+ { 0x00061 , 0x00328 , 0x00105 },
+ { 0x00062 , 0x00307 , 0x01E03 },
+ { 0x00062 , 0x00323 , 0x01E05 },
+ { 0x00062 , 0x00331 , 0x01E07 },
+ { 0x00063 , 0x00301 , 0x00107 },
+ { 0x00063 , 0x00302 , 0x00109 },
+ { 0x00063 , 0x00307 , 0x0010B },
+ { 0x00063 , 0x0030C , 0x0010D },
+ { 0x00063 , 0x00327 , 0x000E7 },
+ { 0x00064 , 0x00307 , 0x01E0B },
+ { 0x00064 , 0x0030C , 0x0010F },
+ { 0x00064 , 0x00323 , 0x01E0D },
+ { 0x00064 , 0x00327 , 0x01E11 },
+ { 0x00064 , 0x0032D , 0x01E13 },
+ { 0x00064 , 0x00331 , 0x01E0F },
+ { 0x00065 , 0x00300 , 0x000E8 },
+ { 0x00065 , 0x00301 , 0x000E9 },
+ { 0x00065 , 0x00302 , 0x000EA },
+ { 0x00065 , 0x00303 , 0x01EBD },
+ { 0x00065 , 0x00304 , 0x00113 },
+ { 0x00065 , 0x00306 , 0x00115 },
+ { 0x00065 , 0x00307 , 0x00117 },
+ { 0x00065 , 0x00308 , 0x000EB },
+ { 0x00065 , 0x00309 , 0x01EBB },
+ { 0x00065 , 0x0030C , 0x0011B },
+ { 0x00065 , 0x0030F , 0x00205 },
+ { 0x00065 , 0x00311 , 0x00207 },
+ { 0x00065 , 0x00323 , 0x01EB9 },
+ { 0x00065 , 0x00327 , 0x00229 },
+ { 0x00065 , 0x00328 , 0x00119 },
+ { 0x00065 , 0x0032D , 0x01E19 },
+ { 0x00065 , 0x00330 , 0x01E1B },
+ { 0x00066 , 0x00307 , 0x01E1F },
+ { 0x00067 , 0x00301 , 0x001F5 },
+ { 0x00067 , 0x00302 , 0x0011D },
+ { 0x00067 , 0x00304 , 0x01E21 },
+ { 0x00067 , 0x00306 , 0x0011F },
+ { 0x00067 , 0x00307 , 0x00121 },
+ { 0x00067 , 0x0030C , 0x001E7 },
+ { 0x00067 , 0x00327 , 0x00123 },
+ { 0x00068 , 0x00302 , 0x00125 },
+ { 0x00068 , 0x00307 , 0x01E23 },
+ { 0x00068 , 0x00308 , 0x01E27 },
+ { 0x00068 , 0x0030C , 0x0021F },
+ { 0x00068 , 0x00323 , 0x01E25 },
+ { 0x00068 , 0x00327 , 0x01E29 },
+ { 0x00068 , 0x0032E , 0x01E2B },
+ { 0x00068 , 0x00331 , 0x01E96 },
+ { 0x00069 , 0x00300 , 0x000EC },
+ { 0x00069 , 0x00301 , 0x000ED },
+ { 0x00069 , 0x00302 , 0x000EE },
+ { 0x00069 , 0x00303 , 0x00129 },
+ { 0x00069 , 0x00304 , 0x0012B },
+ { 0x00069 , 0x00306 , 0x0012D },
+ { 0x00069 , 0x00308 , 0x000EF },
+ { 0x00069 , 0x00309 , 0x01EC9 },
+ { 0x00069 , 0x0030C , 0x001D0 },
+ { 0x00069 , 0x0030F , 0x00209 },
+ { 0x00069 , 0x00311 , 0x0020B },
+ { 0x00069 , 0x00323 , 0x01ECB },
+ { 0x00069 , 0x00328 , 0x0012F },
+ { 0x00069 , 0x00330 , 0x01E2D },
+ { 0x0006A , 0x00302 , 0x00135 },
+ { 0x0006A , 0x0030C , 0x001F0 },
+ { 0x0006B , 0x00301 , 0x01E31 },
+ { 0x0006B , 0x0030C , 0x001E9 },
+ { 0x0006B , 0x00323 , 0x01E33 },
+ { 0x0006B , 0x00327 , 0x00137 },
+ { 0x0006B , 0x00331 , 0x01E35 },
+ { 0x0006C , 0x00301 , 0x0013A },
+ { 0x0006C , 0x0030C , 0x0013E },
+ { 0x0006C , 0x00323 , 0x01E37 },
+ { 0x0006C , 0x00327 , 0x0013C },
+ { 0x0006C , 0x0032D , 0x01E3D },
+ { 0x0006C , 0x00331 , 0x01E3B },
+ { 0x0006D , 0x00301 , 0x01E3F },
+ { 0x0006D , 0x00307 , 0x01E41 },
+ { 0x0006D , 0x00323 , 0x01E43 },
+ { 0x0006E , 0x00300 , 0x001F9 },
+ { 0x0006E , 0x00301 , 0x00144 },
+ { 0x0006E , 0x00303 , 0x000F1 },
+ { 0x0006E , 0x00307 , 0x01E45 },
+ { 0x0006E , 0x0030C , 0x00148 },
+ { 0x0006E , 0x00323 , 0x01E47 },
+ { 0x0006E , 0x00327 , 0x00146 },
+ { 0x0006E , 0x0032D , 0x01E4B },
+ { 0x0006E , 0x00331 , 0x01E49 },
+ { 0x0006F , 0x00300 , 0x000F2 },
+ { 0x0006F , 0x00301 , 0x000F3 },
+ { 0x0006F , 0x00302 , 0x000F4 },
+ { 0x0006F , 0x00303 , 0x000F5 },
+ { 0x0006F , 0x00304 , 0x0014D },
+ { 0x0006F , 0x00306 , 0x0014F },
+ { 0x0006F , 0x00307 , 0x0022F },
+ { 0x0006F , 0x00308 , 0x000F6 },
+ { 0x0006F , 0x00309 , 0x01ECF },
+ { 0x0006F , 0x0030B , 0x00151 },
+ { 0x0006F , 0x0030C , 0x001D2 },
+ { 0x0006F , 0x0030F , 0x0020D },
+ { 0x0006F , 0x00311 , 0x0020F },
+ { 0x0006F , 0x0031B , 0x001A1 },
+ { 0x0006F , 0x00323 , 0x01ECD },
+ { 0x0006F , 0x00328 , 0x001EB },
+ { 0x00070 , 0x00301 , 0x01E55 },
+ { 0x00070 , 0x00307 , 0x01E57 },
+ { 0x00072 , 0x00301 , 0x00155 },
+ { 0x00072 , 0x00307 , 0x01E59 },
+ { 0x00072 , 0x0030C , 0x00159 },
+ { 0x00072 , 0x0030F , 0x00211 },
+ { 0x00072 , 0x00311 , 0x00213 },
+ { 0x00072 , 0x00323 , 0x01E5B },
+ { 0x00072 , 0x00327 , 0x00157 },
+ { 0x00072 , 0x00331 , 0x01E5F },
+ { 0x00073 , 0x00301 , 0x0015B },
+ { 0x00073 , 0x00302 , 0x0015D },
+ { 0x00073 , 0x00307 , 0x01E61 },
+ { 0x00073 , 0x0030C , 0x00161 },
+ { 0x00073 , 0x00323 , 0x01E63 },
+ { 0x00073 , 0x00326 , 0x00219 },
+ { 0x00073 , 0x00327 , 0x0015F },
+ { 0x00074 , 0x00307 , 0x01E6B },
+ { 0x00074 , 0x00308 , 0x01E97 },
+ { 0x00074 , 0x0030C , 0x00165 },
+ { 0x00074 , 0x00323 , 0x01E6D },
+ { 0x00074 , 0x00326 , 0x0021B },
+ { 0x00074 , 0x00327 , 0x00163 },
+ { 0x00074 , 0x0032D , 0x01E71 },
+ { 0x00074 , 0x00331 , 0x01E6F },
+ { 0x00075 , 0x00300 , 0x000F9 },
+ { 0x00075 , 0x00301 , 0x000FA },
+ { 0x00075 , 0x00302 , 0x000FB },
+ { 0x00075 , 0x00303 , 0x00169 },
+ { 0x00075 , 0x00304 , 0x0016B },
+ { 0x00075 , 0x00306 , 0x0016D },
+ { 0x00075 , 0x00308 , 0x000FC },
+ { 0x00075 , 0x00309 , 0x01EE7 },
+ { 0x00075 , 0x0030A , 0x0016F },
+ { 0x00075 , 0x0030B , 0x00171 },
+ { 0x00075 , 0x0030C , 0x001D4 },
+ { 0x00075 , 0x0030F , 0x00215 },
+ { 0x00075 , 0x00311 , 0x00217 },
+ { 0x00075 , 0x0031B , 0x001B0 },
+ { 0x00075 , 0x00323 , 0x01EE5 },
+ { 0x00075 , 0x00324 , 0x01E73 },
+ { 0x00075 , 0x00328 , 0x00173 },
+ { 0x00075 , 0x0032D , 0x01E77 },
+ { 0x00075 , 0x00330 , 0x01E75 },
+ { 0x00076 , 0x00303 , 0x01E7D },
+ { 0x00076 , 0x00323 , 0x01E7F },
+ { 0x00077 , 0x00300 , 0x01E81 },
+ { 0x00077 , 0x00301 , 0x01E83 },
+ { 0x00077 , 0x00302 , 0x00175 },
+ { 0x00077 , 0x00307 , 0x01E87 },
+ { 0x00077 , 0x00308 , 0x01E85 },
+ { 0x00077 , 0x0030A , 0x01E98 },
+ { 0x00077 , 0x00323 , 0x01E89 },
+ { 0x00078 , 0x00307 , 0x01E8B },
+ { 0x00078 , 0x00308 , 0x01E8D },
+ { 0x00079 , 0x00300 , 0x01EF3 },
+ { 0x00079 , 0x00301 , 0x000FD },
+ { 0x00079 , 0x00302 , 0x00177 },
+ { 0x00079 , 0x00303 , 0x01EF9 },
+ { 0x00079 , 0x00304 , 0x00233 },
+ { 0x00079 , 0x00307 , 0x01E8F },
+ { 0x00079 , 0x00308 , 0x000FF },
+ { 0x00079 , 0x00309 , 0x01EF7 },
+ { 0x00079 , 0x0030A , 0x01E99 },
+ { 0x00079 , 0x00323 , 0x01EF5 },
+ { 0x0007A , 0x00301 , 0x0017A },
+ { 0x0007A , 0x00302 , 0x01E91 },
+ { 0x0007A , 0x00307 , 0x0017C },
+ { 0x0007A , 0x0030C , 0x0017E },
+ { 0x0007A , 0x00323 , 0x01E93 },
+ { 0x0007A , 0x00331 , 0x01E95 },
+ { 0x000A8 , 0x00300 , 0x01FED },
+ { 0x000A8 , 0x00301 , 0x00385 },
+ { 0x000A8 , 0x00342 , 0x01FC1 },
+ { 0x000C2 , 0x00300 , 0x01EA6 },
+ { 0x000C2 , 0x00301 , 0x01EA4 },
+ { 0x000C2 , 0x00303 , 0x01EAA },
+ { 0x000C2 , 0x00309 , 0x01EA8 },
+ { 0x000C4 , 0x00304 , 0x001DE },
+ { 0x000C5 , 0x00301 , 0x001FA },
+ { 0x000C6 , 0x00301 , 0x001FC },
+ { 0x000C6 , 0x00304 , 0x001E2 },
+ { 0x000C7 , 0x00301 , 0x01E08 },
+ { 0x000CA , 0x00300 , 0x01EC0 },
+ { 0x000CA , 0x00301 , 0x01EBE },
+ { 0x000CA , 0x00303 , 0x01EC4 },
+ { 0x000CA , 0x00309 , 0x01EC2 },
+ { 0x000CF , 0x00301 , 0x01E2E },
+ { 0x000D4 , 0x00300 , 0x01ED2 },
+ { 0x000D4 , 0x00301 , 0x01ED0 },
+ { 0x000D4 , 0x00303 , 0x01ED6 },
+ { 0x000D4 , 0x00309 , 0x01ED4 },
+ { 0x000D5 , 0x00301 , 0x01E4C },
+ { 0x000D5 , 0x00304 , 0x0022C },
+ { 0x000D5 , 0x00308 , 0x01E4E },
+ { 0x000D6 , 0x00304 , 0x0022A },
+ { 0x000D8 , 0x00301 , 0x001FE },
+ { 0x000DC , 0x00300 , 0x001DB },
+ { 0x000DC , 0x00301 , 0x001D7 },
+ { 0x000DC , 0x00304 , 0x001D5 },
+ { 0x000DC , 0x0030C , 0x001D9 },
+ { 0x000E2 , 0x00300 , 0x01EA7 },
+ { 0x000E2 , 0x00301 , 0x01EA5 },
+ { 0x000E2 , 0x00303 , 0x01EAB },
+ { 0x000E2 , 0x00309 , 0x01EA9 },
+ { 0x000E4 , 0x00304 , 0x001DF },
+ { 0x000E5 , 0x00301 , 0x001FB },
+ { 0x000E6 , 0x00301 , 0x001FD },
+ { 0x000E6 , 0x00304 , 0x001E3 },
+ { 0x000E7 , 0x00301 , 0x01E09 },
+ { 0x000EA , 0x00300 , 0x01EC1 },
+ { 0x000EA , 0x00301 , 0x01EBF },
+ { 0x000EA , 0x00303 , 0x01EC5 },
+ { 0x000EA , 0x00309 , 0x01EC3 },
+ { 0x000EF , 0x00301 , 0x01E2F },
+ { 0x000F4 , 0x00300 , 0x01ED3 },
+ { 0x000F4 , 0x00301 , 0x01ED1 },
+ { 0x000F4 , 0x00303 , 0x01ED7 },
+ { 0x000F4 , 0x00309 , 0x01ED5 },
+ { 0x000F5 , 0x00301 , 0x01E4D },
+ { 0x000F5 , 0x00304 , 0x0022D },
+ { 0x000F5 , 0x00308 , 0x01E4F },
+ { 0x000F6 , 0x00304 , 0x0022B },
+ { 0x000F8 , 0x00301 , 0x001FF },
+ { 0x000FC , 0x00300 , 0x001DC },
+ { 0x000FC , 0x00301 , 0x001D8 },
+ { 0x000FC , 0x00304 , 0x001D6 },
+ { 0x000FC , 0x0030C , 0x001DA },
+ { 0x00102 , 0x00300 , 0x01EB0 },
+ { 0x00102 , 0x00301 , 0x01EAE },
+ { 0x00102 , 0x00303 , 0x01EB4 },
+ { 0x00102 , 0x00309 , 0x01EB2 },
+ { 0x00103 , 0x00300 , 0x01EB1 },
+ { 0x00103 , 0x00301 , 0x01EAF },
+ { 0x00103 , 0x00303 , 0x01EB5 },
+ { 0x00103 , 0x00309 , 0x01EB3 },
+ { 0x00112 , 0x00300 , 0x01E14 },
+ { 0x00112 , 0x00301 , 0x01E16 },
+ { 0x00113 , 0x00300 , 0x01E15 },
+ { 0x00113 , 0x00301 , 0x01E17 },
+ { 0x0014C , 0x00300 , 0x01E50 },
+ { 0x0014C , 0x00301 , 0x01E52 },
+ { 0x0014D , 0x00300 , 0x01E51 },
+ { 0x0014D , 0x00301 , 0x01E53 },
+ { 0x0015A , 0x00307 , 0x01E64 },
+ { 0x0015B , 0x00307 , 0x01E65 },
+ { 0x00160 , 0x00307 , 0x01E66 },
+ { 0x00161 , 0x00307 , 0x01E67 },
+ { 0x00168 , 0x00301 , 0x01E78 },
+ { 0x00169 , 0x00301 , 0x01E79 },
+ { 0x0016A , 0x00308 , 0x01E7A },
+ { 0x0016B , 0x00308 , 0x01E7B },
+ { 0x0017F , 0x00307 , 0x01E9B },
+ { 0x001A0 , 0x00300 , 0x01EDC },
+ { 0x001A0 , 0x00301 , 0x01EDA },
+ { 0x001A0 , 0x00303 , 0x01EE0 },
+ { 0x001A0 , 0x00309 , 0x01EDE },
+ { 0x001A0 , 0x00323 , 0x01EE2 },
+ { 0x001A1 , 0x00300 , 0x01EDD },
+ { 0x001A1 , 0x00301 , 0x01EDB },
+ { 0x001A1 , 0x00303 , 0x01EE1 },
+ { 0x001A1 , 0x00309 , 0x01EDF },
+ { 0x001A1 , 0x00323 , 0x01EE3 },
+ { 0x001AF , 0x00300 , 0x01EEA },
+ { 0x001AF , 0x00301 , 0x01EE8 },
+ { 0x001AF , 0x00303 , 0x01EEE },
+ { 0x001AF , 0x00309 , 0x01EEC },
+ { 0x001AF , 0x00323 , 0x01EF0 },
+ { 0x001B0 , 0x00300 , 0x01EEB },
+ { 0x001B0 , 0x00301 , 0x01EE9 },
+ { 0x001B0 , 0x00303 , 0x01EEF },
+ { 0x001B0 , 0x00309 , 0x01EED },
+ { 0x001B0 , 0x00323 , 0x01EF1 },
+ { 0x001B7 , 0x0030C , 0x001EE },
+ { 0x001EA , 0x00304 , 0x001EC },
+ { 0x001EB , 0x00304 , 0x001ED },
+ { 0x00226 , 0x00304 , 0x001E0 },
+ { 0x00227 , 0x00304 , 0x001E1 },
+ { 0x00228 , 0x00306 , 0x01E1C },
+ { 0x00229 , 0x00306 , 0x01E1D },
+ { 0x0022E , 0x00304 , 0x00230 },
+ { 0x0022F , 0x00304 , 0x00231 },
+ { 0x00292 , 0x0030C , 0x001EF },
+ { 0x00391 , 0x00300 , 0x01FBA },
+ { 0x00391 , 0x00301 , 0x00386 },
+ { 0x00391 , 0x00304 , 0x01FB9 },
+ { 0x00391 , 0x00306 , 0x01FB8 },
+ { 0x00391 , 0x00313 , 0x01F08 },
+ { 0x00391 , 0x00314 , 0x01F09 },
+ { 0x00391 , 0x00345 , 0x01FBC },
+ { 0x00395 , 0x00300 , 0x01FC8 },
+ { 0x00395 , 0x00301 , 0x00388 },
+ { 0x00395 , 0x00313 , 0x01F18 },
+ { 0x00395 , 0x00314 , 0x01F19 },
+ { 0x00397 , 0x00300 , 0x01FCA },
+ { 0x00397 , 0x00301 , 0x00389 },
+ { 0x00397 , 0x00313 , 0x01F28 },
+ { 0x00397 , 0x00314 , 0x01F29 },
+ { 0x00397 , 0x00345 , 0x01FCC },
+ { 0x00399 , 0x00300 , 0x01FDA },
+ { 0x00399 , 0x00301 , 0x0038A },
+ { 0x00399 , 0x00304 , 0x01FD9 },
+ { 0x00399 , 0x00306 , 0x01FD8 },
+ { 0x00399 , 0x00308 , 0x003AA },
+ { 0x00399 , 0x00313 , 0x01F38 },
+ { 0x00399 , 0x00314 , 0x01F39 },
+ { 0x0039F , 0x00300 , 0x01FF8 },
+ { 0x0039F , 0x00301 , 0x0038C },
+ { 0x0039F , 0x00313 , 0x01F48 },
+ { 0x0039F , 0x00314 , 0x01F49 },
+ { 0x003A1 , 0x00314 , 0x01FEC },
+ { 0x003A5 , 0x00300 , 0x01FEA },
+ { 0x003A5 , 0x00301 , 0x0038E },
+ { 0x003A5 , 0x00304 , 0x01FE9 },
+ { 0x003A5 , 0x00306 , 0x01FE8 },
+ { 0x003A5 , 0x00308 , 0x003AB },
+ { 0x003A5 , 0x00314 , 0x01F59 },
+ { 0x003A9 , 0x00300 , 0x01FFA },
+ { 0x003A9 , 0x00301 , 0x0038F },
+ { 0x003A9 , 0x00313 , 0x01F68 },
+ { 0x003A9 , 0x00314 , 0x01F69 },
+ { 0x003A9 , 0x00345 , 0x01FFC },
+ { 0x003AC , 0x00345 , 0x01FB4 },
+ { 0x003AE , 0x00345 , 0x01FC4 },
+ { 0x003B1 , 0x00300 , 0x01F70 },
+ { 0x003B1 , 0x00301 , 0x003AC },
+ { 0x003B1 , 0x00304 , 0x01FB1 },
+ { 0x003B1 , 0x00306 , 0x01FB0 },
+ { 0x003B1 , 0x00313 , 0x01F00 },
+ { 0x003B1 , 0x00314 , 0x01F01 },
+ { 0x003B1 , 0x00342 , 0x01FB6 },
+ { 0x003B1 , 0x00345 , 0x01FB3 },
+ { 0x003B5 , 0x00300 , 0x01F72 },
+ { 0x003B5 , 0x00301 , 0x003AD },
+ { 0x003B5 , 0x00313 , 0x01F10 },
+ { 0x003B5 , 0x00314 , 0x01F11 },
+ { 0x003B7 , 0x00300 , 0x01F74 },
+ { 0x003B7 , 0x00301 , 0x003AE },
+ { 0x003B7 , 0x00313 , 0x01F20 },
+ { 0x003B7 , 0x00314 , 0x01F21 },
+ { 0x003B7 , 0x00342 , 0x01FC6 },
+ { 0x003B7 , 0x00345 , 0x01FC3 },
+ { 0x003B9 , 0x00300 , 0x01F76 },
+ { 0x003B9 , 0x00301 , 0x003AF },
+ { 0x003B9 , 0x00304 , 0x01FD1 },
+ { 0x003B9 , 0x00306 , 0x01FD0 },
+ { 0x003B9 , 0x00308 , 0x003CA },
+ { 0x003B9 , 0x00313 , 0x01F30 },
+ { 0x003B9 , 0x00314 , 0x01F31 },
+ { 0x003B9 , 0x00342 , 0x01FD6 },
+ { 0x003BF , 0x00300 , 0x01F78 },
+ { 0x003BF , 0x00301 , 0x003CC },
+ { 0x003BF , 0x00313 , 0x01F40 },
+ { 0x003BF , 0x00314 , 0x01F41 },
+ { 0x003C1 , 0x00313 , 0x01FE4 },
+ { 0x003C1 , 0x00314 , 0x01FE5 },
+ { 0x003C5 , 0x00300 , 0x01F7A },
+ { 0x003C5 , 0x00301 , 0x003CD },
+ { 0x003C5 , 0x00304 , 0x01FE1 },
+ { 0x003C5 , 0x00306 , 0x01FE0 },
+ { 0x003C5 , 0x00308 , 0x003CB },
+ { 0x003C5 , 0x00313 , 0x01F50 },
+ { 0x003C5 , 0x00314 , 0x01F51 },
+ { 0x003C5 , 0x00342 , 0x01FE6 },
+ { 0x003C9 , 0x00300 , 0x01F7C },
+ { 0x003C9 , 0x00301 , 0x003CE },
+ { 0x003C9 , 0x00313 , 0x01F60 },
+ { 0x003C9 , 0x00314 , 0x01F61 },
+ { 0x003C9 , 0x00342 , 0x01FF6 },
+ { 0x003C9 , 0x00345 , 0x01FF3 },
+ { 0x003CA , 0x00300 , 0x01FD2 },
+ { 0x003CA , 0x00301 , 0x00390 },
+ { 0x003CA , 0x00342 , 0x01FD7 },
+ { 0x003CB , 0x00300 , 0x01FE2 },
+ { 0x003CB , 0x00301 , 0x003B0 },
+ { 0x003CB , 0x00342 , 0x01FE7 },
+ { 0x003CE , 0x00345 , 0x01FF4 },
+ { 0x003D2 , 0x00301 , 0x003D3 },
+ { 0x003D2 , 0x00308 , 0x003D4 },
+ { 0x00406 , 0x00308 , 0x00407 },
+ { 0x00410 , 0x00306 , 0x004D0 },
+ { 0x00410 , 0x00308 , 0x004D2 },
+ { 0x00413 , 0x00301 , 0x00403 },
+ { 0x00415 , 0x00300 , 0x00400 },
+ { 0x00415 , 0x00306 , 0x004D6 },
+ { 0x00415 , 0x00308 , 0x00401 },
+ { 0x00416 , 0x00306 , 0x004C1 },
+ { 0x00416 , 0x00308 , 0x004DC },
+ { 0x00417 , 0x00308 , 0x004DE },
+ { 0x00418 , 0x00300 , 0x0040D },
+ { 0x00418 , 0x00304 , 0x004E2 },
+ { 0x00418 , 0x00306 , 0x00419 },
+ { 0x00418 , 0x00308 , 0x004E4 },
+ { 0x0041A , 0x00301 , 0x0040C },
+ { 0x0041E , 0x00308 , 0x004E6 },
+ { 0x00423 , 0x00304 , 0x004EE },
+ { 0x00423 , 0x00306 , 0x0040E },
+ { 0x00423 , 0x00308 , 0x004F0 },
+ { 0x00423 , 0x0030B , 0x004F2 },
+ { 0x00427 , 0x00308 , 0x004F4 },
+ { 0x0042B , 0x00308 , 0x004F8 },
+ { 0x0042D , 0x00308 , 0x004EC },
+ { 0x00430 , 0x00306 , 0x004D1 },
+ { 0x00430 , 0x00308 , 0x004D3 },
+ { 0x00433 , 0x00301 , 0x00453 },
+ { 0x00435 , 0x00300 , 0x00450 },
+ { 0x00435 , 0x00306 , 0x004D7 },
+ { 0x00435 , 0x00308 , 0x00451 },
+ { 0x00436 , 0x00306 , 0x004C2 },
+ { 0x00436 , 0x00308 , 0x004DD },
+ { 0x00437 , 0x00308 , 0x004DF },
+ { 0x00438 , 0x00300 , 0x0045D },
+ { 0x00438 , 0x00304 , 0x004E3 },
+ { 0x00438 , 0x00306 , 0x00439 },
+ { 0x00438 , 0x00308 , 0x004E5 },
+ { 0x0043A , 0x00301 , 0x0045C },
+ { 0x0043E , 0x00308 , 0x004E7 },
+ { 0x00443 , 0x00304 , 0x004EF },
+ { 0x00443 , 0x00306 , 0x0045E },
+ { 0x00443 , 0x00308 , 0x004F1 },
+ { 0x00443 , 0x0030B , 0x004F3 },
+ { 0x00447 , 0x00308 , 0x004F5 },
+ { 0x0044B , 0x00308 , 0x004F9 },
+ { 0x0044D , 0x00308 , 0x004ED },
+ { 0x00456 , 0x00308 , 0x00457 },
+ { 0x00474 , 0x0030F , 0x00476 },
+ { 0x00475 , 0x0030F , 0x00477 },
+ { 0x004D8 , 0x00308 , 0x004DA },
+ { 0x004D9 , 0x00308 , 0x004DB },
+ { 0x004E8 , 0x00308 , 0x004EA },
+ { 0x004E9 , 0x00308 , 0x004EB },
+ { 0x00627 , 0x00653 , 0x00622 },
+ { 0x00627 , 0x00654 , 0x00623 },
+ { 0x00627 , 0x00655 , 0x00625 },
+ { 0x00648 , 0x00654 , 0x00624 },
+ { 0x0064A , 0x00654 , 0x00626 },
+ { 0x006C1 , 0x00654 , 0x006C2 },
+ { 0x006D2 , 0x00654 , 0x006D3 },
+ { 0x006D5 , 0x00654 , 0x006C0 },
+ { 0x00928 , 0x0093C , 0x00929 },
+ { 0x00930 , 0x0093C , 0x00931 },
+ { 0x00933 , 0x0093C , 0x00934 },
+ { 0x009C7 , 0x009BE , 0x009CB },
+ { 0x009C7 , 0x009D7 , 0x009CC },
+ { 0x00B47 , 0x00B3E , 0x00B4B },
+ { 0x00B47 , 0x00B56 , 0x00B48 },
+ { 0x00B47 , 0x00B57 , 0x00B4C },
+ { 0x00B92 , 0x00BD7 , 0x00B94 },
+ { 0x00BC6 , 0x00BBE , 0x00BCA },
+ { 0x00BC6 , 0x00BD7 , 0x00BCC },
+ { 0x00BC7 , 0x00BBE , 0x00BCB },
+ { 0x00C46 , 0x00C56 , 0x00C48 },
+ { 0x00CBF , 0x00CD5 , 0x00CC0 },
+ { 0x00CC6 , 0x00CC2 , 0x00CCA },
+ { 0x00CC6 , 0x00CD5 , 0x00CC7 },
+ { 0x00CC6 , 0x00CD6 , 0x00CC8 },
+ { 0x00CCA , 0x00CD5 , 0x00CCB },
+ { 0x00D46 , 0x00D3E , 0x00D4A },
+ { 0x00D46 , 0x00D57 , 0x00D4C },
+ { 0x00D47 , 0x00D3E , 0x00D4B },
+ { 0x00DD9 , 0x00DCA , 0x00DDA },
+ { 0x00DD9 , 0x00DCF , 0x00DDC },
+ { 0x00DD9 , 0x00DDF , 0x00DDE },
+ { 0x00DDC , 0x00DCA , 0x00DDD },
+ { 0x01025 , 0x0102E , 0x01026 },
+ { 0x01B05 , 0x01B35 , 0x01B06 },
+ { 0x01B07 , 0x01B35 , 0x01B08 },
+ { 0x01B09 , 0x01B35 , 0x01B0A },
+ { 0x01B0B , 0x01B35 , 0x01B0C },
+ { 0x01B0D , 0x01B35 , 0x01B0E },
+ { 0x01B11 , 0x01B35 , 0x01B12 },
+ { 0x01B3A , 0x01B35 , 0x01B3B },
+ { 0x01B3C , 0x01B35 , 0x01B3D },
+ { 0x01B3E , 0x01B35 , 0x01B40 },
+ { 0x01B3F , 0x01B35 , 0x01B41 },
+ { 0x01B42 , 0x01B35 , 0x01B43 },
+ { 0x01E36 , 0x00304 , 0x01E38 },
+ { 0x01E37 , 0x00304 , 0x01E39 },
+ { 0x01E5A , 0x00304 , 0x01E5C },
+ { 0x01E5B , 0x00304 , 0x01E5D },
+ { 0x01E62 , 0x00307 , 0x01E68 },
+ { 0x01E63 , 0x00307 , 0x01E69 },
+ { 0x01EA0 , 0x00302 , 0x01EAC },
+ { 0x01EA0 , 0x00306 , 0x01EB6 },
+ { 0x01EA1 , 0x00302 , 0x01EAD },
+ { 0x01EA1 , 0x00306 , 0x01EB7 },
+ { 0x01EB8 , 0x00302 , 0x01EC6 },
+ { 0x01EB9 , 0x00302 , 0x01EC7 },
+ { 0x01ECC , 0x00302 , 0x01ED8 },
+ { 0x01ECD , 0x00302 , 0x01ED9 },
+ { 0x01F00 , 0x00300 , 0x01F02 },
+ { 0x01F00 , 0x00301 , 0x01F04 },
+ { 0x01F00 , 0x00342 , 0x01F06 },
+ { 0x01F00 , 0x00345 , 0x01F80 },
+ { 0x01F01 , 0x00300 , 0x01F03 },
+ { 0x01F01 , 0x00301 , 0x01F05 },
+ { 0x01F01 , 0x00342 , 0x01F07 },
+ { 0x01F01 , 0x00345 , 0x01F81 },
+ { 0x01F02 , 0x00345 , 0x01F82 },
+ { 0x01F03 , 0x00345 , 0x01F83 },
+ { 0x01F04 , 0x00345 , 0x01F84 },
+ { 0x01F05 , 0x00345 , 0x01F85 },
+ { 0x01F06 , 0x00345 , 0x01F86 },
+ { 0x01F07 , 0x00345 , 0x01F87 },
+ { 0x01F08 , 0x00300 , 0x01F0A },
+ { 0x01F08 , 0x00301 , 0x01F0C },
+ { 0x01F08 , 0x00342 , 0x01F0E },
+ { 0x01F08 , 0x00345 , 0x01F88 },
+ { 0x01F09 , 0x00300 , 0x01F0B },
+ { 0x01F09 , 0x00301 , 0x01F0D },
+ { 0x01F09 , 0x00342 , 0x01F0F },
+ { 0x01F09 , 0x00345 , 0x01F89 },
+ { 0x01F0A , 0x00345 , 0x01F8A },
+ { 0x01F0B , 0x00345 , 0x01F8B },
+ { 0x01F0C , 0x00345 , 0x01F8C },
+ { 0x01F0D , 0x00345 , 0x01F8D },
+ { 0x01F0E , 0x00345 , 0x01F8E },
+ { 0x01F0F , 0x00345 , 0x01F8F },
+ { 0x01F10 , 0x00300 , 0x01F12 },
+ { 0x01F10 , 0x00301 , 0x01F14 },
+ { 0x01F11 , 0x00300 , 0x01F13 },
+ { 0x01F11 , 0x00301 , 0x01F15 },
+ { 0x01F18 , 0x00300 , 0x01F1A },
+ { 0x01F18 , 0x00301 , 0x01F1C },
+ { 0x01F19 , 0x00300 , 0x01F1B },
+ { 0x01F19 , 0x00301 , 0x01F1D },
+ { 0x01F20 , 0x00300 , 0x01F22 },
+ { 0x01F20 , 0x00301 , 0x01F24 },
+ { 0x01F20 , 0x00342 , 0x01F26 },
+ { 0x01F20 , 0x00345 , 0x01F90 },
+ { 0x01F21 , 0x00300 , 0x01F23 },
+ { 0x01F21 , 0x00301 , 0x01F25 },
+ { 0x01F21 , 0x00342 , 0x01F27 },
+ { 0x01F21 , 0x00345 , 0x01F91 },
+ { 0x01F22 , 0x00345 , 0x01F92 },
+ { 0x01F23 , 0x00345 , 0x01F93 },
+ { 0x01F24 , 0x00345 , 0x01F94 },
+ { 0x01F25 , 0x00345 , 0x01F95 },
+ { 0x01F26 , 0x00345 , 0x01F96 },
+ { 0x01F27 , 0x00345 , 0x01F97 },
+ { 0x01F28 , 0x00300 , 0x01F2A },
+ { 0x01F28 , 0x00301 , 0x01F2C },
+ { 0x01F28 , 0x00342 , 0x01F2E },
+ { 0x01F28 , 0x00345 , 0x01F98 },
+ { 0x01F29 , 0x00300 , 0x01F2B },
+ { 0x01F29 , 0x00301 , 0x01F2D },
+ { 0x01F29 , 0x00342 , 0x01F2F },
+ { 0x01F29 , 0x00345 , 0x01F99 },
+ { 0x01F2A , 0x00345 , 0x01F9A },
+ { 0x01F2B , 0x00345 , 0x01F9B },
+ { 0x01F2C , 0x00345 , 0x01F9C },
+ { 0x01F2D , 0x00345 , 0x01F9D },
+ { 0x01F2E , 0x00345 , 0x01F9E },
+ { 0x01F2F , 0x00345 , 0x01F9F },
+ { 0x01F30 , 0x00300 , 0x01F32 },
+ { 0x01F30 , 0x00301 , 0x01F34 },
+ { 0x01F30 , 0x00342 , 0x01F36 },
+ { 0x01F31 , 0x00300 , 0x01F33 },
+ { 0x01F31 , 0x00301 , 0x01F35 },
+ { 0x01F31 , 0x00342 , 0x01F37 },
+ { 0x01F38 , 0x00300 , 0x01F3A },
+ { 0x01F38 , 0x00301 , 0x01F3C },
+ { 0x01F38 , 0x00342 , 0x01F3E },
+ { 0x01F39 , 0x00300 , 0x01F3B },
+ { 0x01F39 , 0x00301 , 0x01F3D },
+ { 0x01F39 , 0x00342 , 0x01F3F },
+ { 0x01F40 , 0x00300 , 0x01F42 },
+ { 0x01F40 , 0x00301 , 0x01F44 },
+ { 0x01F41 , 0x00300 , 0x01F43 },
+ { 0x01F41 , 0x00301 , 0x01F45 },
+ { 0x01F48 , 0x00300 , 0x01F4A },
+ { 0x01F48 , 0x00301 , 0x01F4C },
+ { 0x01F49 , 0x00300 , 0x01F4B },
+ { 0x01F49 , 0x00301 , 0x01F4D },
+ { 0x01F50 , 0x00300 , 0x01F52 },
+ { 0x01F50 , 0x00301 , 0x01F54 },
+ { 0x01F50 , 0x00342 , 0x01F56 },
+ { 0x01F51 , 0x00300 , 0x01F53 },
+ { 0x01F51 , 0x00301 , 0x01F55 },
+ { 0x01F51 , 0x00342 , 0x01F57 },
+ { 0x01F59 , 0x00300 , 0x01F5B },
+ { 0x01F59 , 0x00301 , 0x01F5D },
+ { 0x01F59 , 0x00342 , 0x01F5F },
+ { 0x01F60 , 0x00300 , 0x01F62 },
+ { 0x01F60 , 0x00301 , 0x01F64 },
+ { 0x01F60 , 0x00342 , 0x01F66 },
+ { 0x01F60 , 0x00345 , 0x01FA0 },
+ { 0x01F61 , 0x00300 , 0x01F63 },
+ { 0x01F61 , 0x00301 , 0x01F65 },
+ { 0x01F61 , 0x00342 , 0x01F67 },
+ { 0x01F61 , 0x00345 , 0x01FA1 },
+ { 0x01F62 , 0x00345 , 0x01FA2 },
+ { 0x01F63 , 0x00345 , 0x01FA3 },
+ { 0x01F64 , 0x00345 , 0x01FA4 },
+ { 0x01F65 , 0x00345 , 0x01FA5 },
+ { 0x01F66 , 0x00345 , 0x01FA6 },
+ { 0x01F67 , 0x00345 , 0x01FA7 },
+ { 0x01F68 , 0x00300 , 0x01F6A },
+ { 0x01F68 , 0x00301 , 0x01F6C },
+ { 0x01F68 , 0x00342 , 0x01F6E },
+ { 0x01F68 , 0x00345 , 0x01FA8 },
+ { 0x01F69 , 0x00300 , 0x01F6B },
+ { 0x01F69 , 0x00301 , 0x01F6D },
+ { 0x01F69 , 0x00342 , 0x01F6F },
+ { 0x01F69 , 0x00345 , 0x01FA9 },
+ { 0x01F6A , 0x00345 , 0x01FAA },
+ { 0x01F6B , 0x00345 , 0x01FAB },
+ { 0x01F6C , 0x00345 , 0x01FAC },
+ { 0x01F6D , 0x00345 , 0x01FAD },
+ { 0x01F6E , 0x00345 , 0x01FAE },
+ { 0x01F6F , 0x00345 , 0x01FAF },
+ { 0x01F70 , 0x00345 , 0x01FB2 },
+ { 0x01F74 , 0x00345 , 0x01FC2 },
+ { 0x01F7C , 0x00345 , 0x01FF2 },
+ { 0x01FB6 , 0x00345 , 0x01FB7 },
+ { 0x01FBF , 0x00300 , 0x01FCD },
+ { 0x01FBF , 0x00301 , 0x01FCE },
+ { 0x01FBF , 0x00342 , 0x01FCF },
+ { 0x01FC6 , 0x00345 , 0x01FC7 },
+ { 0x01FF6 , 0x00345 , 0x01FF7 },
+ { 0x01FFE , 0x00300 , 0x01FDD },
+ { 0x01FFE , 0x00301 , 0x01FDE },
+ { 0x01FFE , 0x00342 , 0x01FDF },
+ { 0x02190 , 0x00338 , 0x0219A },
+ { 0x02192 , 0x00338 , 0x0219B },
+ { 0x02194 , 0x00338 , 0x021AE },
+ { 0x021D0 , 0x00338 , 0x021CD },
+ { 0x021D2 , 0x00338 , 0x021CF },
+ { 0x021D4 , 0x00338 , 0x021CE },
+ { 0x02203 , 0x00338 , 0x02204 },
+ { 0x02208 , 0x00338 , 0x02209 },
+ { 0x0220B , 0x00338 , 0x0220C },
+ { 0x02223 , 0x00338 , 0x02224 },
+ { 0x02225 , 0x00338 , 0x02226 },
+ { 0x0223C , 0x00338 , 0x02241 },
+ { 0x02243 , 0x00338 , 0x02244 },
+ { 0x02245 , 0x00338 , 0x02247 },
+ { 0x02248 , 0x00338 , 0x02249 },
+ { 0x0224D , 0x00338 , 0x0226D },
+ { 0x02261 , 0x00338 , 0x02262 },
+ { 0x02264 , 0x00338 , 0x02270 },
+ { 0x02265 , 0x00338 , 0x02271 },
+ { 0x02272 , 0x00338 , 0x02274 },
+ { 0x02273 , 0x00338 , 0x02275 },
+ { 0x02276 , 0x00338 , 0x02278 },
+ { 0x02277 , 0x00338 , 0x02279 },
+ { 0x0227A , 0x00338 , 0x02280 },
+ { 0x0227B , 0x00338 , 0x02281 },
+ { 0x0227C , 0x00338 , 0x022E0 },
+ { 0x0227D , 0x00338 , 0x022E1 },
+ { 0x02282 , 0x00338 , 0x02284 },
+ { 0x02283 , 0x00338 , 0x02285 },
+ { 0x02286 , 0x00338 , 0x02288 },
+ { 0x02287 , 0x00338 , 0x02289 },
+ { 0x02291 , 0x00338 , 0x022E2 },
+ { 0x02292 , 0x00338 , 0x022E3 },
+ { 0x022A2 , 0x00338 , 0x022AC },
+ { 0x022A8 , 0x00338 , 0x022AD },
+ { 0x022A9 , 0x00338 , 0x022AE },
+ { 0x022AB , 0x00338 , 0x022AF },
+ { 0x022B2 , 0x00338 , 0x022EA },
+ { 0x022B3 , 0x00338 , 0x022EB },
+ { 0x022B4 , 0x00338 , 0x022EC },
+ { 0x022B5 , 0x00338 , 0x022ED },
+ { 0x03046 , 0x03099 , 0x03094 },
+ { 0x0304B , 0x03099 , 0x0304C },
+ { 0x0304D , 0x03099 , 0x0304E },
+ { 0x0304F , 0x03099 , 0x03050 },
+ { 0x03051 , 0x03099 , 0x03052 },
+ { 0x03053 , 0x03099 , 0x03054 },
+ { 0x03055 , 0x03099 , 0x03056 },
+ { 0x03057 , 0x03099 , 0x03058 },
+ { 0x03059 , 0x03099 , 0x0305A },
+ { 0x0305B , 0x03099 , 0x0305C },
+ { 0x0305D , 0x03099 , 0x0305E },
+ { 0x0305F , 0x03099 , 0x03060 },
+ { 0x03061 , 0x03099 , 0x03062 },
+ { 0x03064 , 0x03099 , 0x03065 },
+ { 0x03066 , 0x03099 , 0x03067 },
+ { 0x03068 , 0x03099 , 0x03069 },
+ { 0x0306F , 0x03099 , 0x03070 },
+ { 0x0306F , 0x0309A , 0x03071 },
+ { 0x03072 , 0x03099 , 0x03073 },
+ { 0x03072 , 0x0309A , 0x03074 },
+ { 0x03075 , 0x03099 , 0x03076 },
+ { 0x03075 , 0x0309A , 0x03077 },
+ { 0x03078 , 0x03099 , 0x03079 },
+ { 0x03078 , 0x0309A , 0x0307A },
+ { 0x0307B , 0x03099 , 0x0307C },
+ { 0x0307B , 0x0309A , 0x0307D },
+ { 0x0309D , 0x03099 , 0x0309E },
+ { 0x030A6 , 0x03099 , 0x030F4 },
+ { 0x030AB , 0x03099 , 0x030AC },
+ { 0x030AD , 0x03099 , 0x030AE },
+ { 0x030AF , 0x03099 , 0x030B0 },
+ { 0x030B1 , 0x03099 , 0x030B2 },
+ { 0x030B3 , 0x03099 , 0x030B4 },
+ { 0x030B5 , 0x03099 , 0x030B6 },
+ { 0x030B7 , 0x03099 , 0x030B8 },
+ { 0x030B9 , 0x03099 , 0x030BA },
+ { 0x030BB , 0x03099 , 0x030BC },
+ { 0x030BD , 0x03099 , 0x030BE },
+ { 0x030BF , 0x03099 , 0x030C0 },
+ { 0x030C1 , 0x03099 , 0x030C2 },
+ { 0x030C4 , 0x03099 , 0x030C5 },
+ { 0x030C6 , 0x03099 , 0x030C7 },
+ { 0x030C8 , 0x03099 , 0x030C9 },
+ { 0x030CF , 0x03099 , 0x030D0 },
+ { 0x030CF , 0x0309A , 0x030D1 },
+ { 0x030D2 , 0x03099 , 0x030D3 },
+ { 0x030D2 , 0x0309A , 0x030D4 },
+ { 0x030D5 , 0x03099 , 0x030D6 },
+ { 0x030D5 , 0x0309A , 0x030D7 },
+ { 0x030D8 , 0x03099 , 0x030D9 },
+ { 0x030D8 , 0x0309A , 0x030DA },
+ { 0x030DB , 0x03099 , 0x030DC },
+ { 0x030DB , 0x0309A , 0x030DD },
+ { 0x030EF , 0x03099 , 0x030F7 },
+ { 0x030F0 , 0x03099 , 0x030F8 },
+ { 0x030F1 , 0x03099 , 0x030F9 },
+ { 0x030F2 , 0x03099 , 0x030FA },
+ { 0x030FD , 0x03099 , 0x030FE },
+ { 0x11099 , 0x110BA , 0x1109A },
+ { 0x1109B , 0x110BA , 0x1109C },
+ { 0x110A5 , 0x110BA , 0x110AB },
+};
+
+#define CANONICAL_CLASS_MIN 0x0300
+#define CANONICAL_CLASS_MAX 0x1D244
+
+#define IS_DECOMPOSABLE_BLOCK(uc) \
+ (((uc)>>8) <= 0x1D2 && u_decomposable_blocks[(uc)>>8])
+static const char u_decomposable_blocks[0x1D2+1] = {
+ 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,1,1,0,0,
+ 1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,
+ 0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
+};
+
+/* Get Canonical Combining Class(CCC). */
+#define CCC(uc) \
+ (((uc) > 0x1D244)?0:\
+ ccc_val[ccc_val_index[ccc_index[(uc)>>8]][((uc)>>4)&0x0F]][(uc)&0x0F])
+
+/* The table of the value of Canonical Cimbining Class */
+static const unsigned char ccc_val[][16] = {
+ /* idx=0: XXXX0 - XXXXF */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=1: 00300 - 0030F */
+ {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },
+ /* idx=2: 00310 - 0031F */
+ {230, 230, 230, 230, 230, 232, 220, 220, 220, 220, 232, 216, 220, 220, 220, 220 },
+ /* idx=3: 00320 - 0032F */
+ {220, 202, 202, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 220, 220, 220 },
+ /* idx=4: 00330 - 0033F */
+ {220, 220, 220, 220, 1, 1, 1, 1, 1, 220, 220, 220, 220, 230, 230, 230 },
+ /* idx=5: 00340 - 0034F */
+ {230, 230, 230, 230, 230, 240, 230, 220, 220, 220, 230, 230, 230, 220, 220, 0 },
+ /* idx=6: 00350 - 0035F */
+ {230, 230, 230, 220, 220, 220, 220, 230, 232, 220, 220, 230, 233, 234, 234, 233 },
+ /* idx=7: 00360 - 0036F */
+ {234, 234, 233, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },
+ /* idx=8: 00480 - 0048F */
+ {0, 0, 0, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=9: 00590 - 0059F */
+ {0, 220, 230, 230, 230, 230, 220, 230, 230, 230, 222, 220, 230, 230, 230, 230 },
+ /* idx=10: 005A0 - 005AF */
+ {230, 230, 220, 220, 220, 220, 220, 220, 230, 230, 220, 230, 230, 222, 228, 230 },
+ /* idx=11: 005B0 - 005BF */
+ {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23 },
+ /* idx=12: 005C0 - 005CF */
+ {0, 24, 25, 0, 230, 220, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=13: 00610 - 0061F */
+ {230, 230, 230, 230, 230, 230, 230, 230, 30, 31, 32, 0, 0, 0, 0, 0 },
+ /* idx=14: 00640 - 0064F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31 },
+ /* idx=15: 00650 - 0065F */
+ {32, 33, 34, 230, 230, 220, 220, 230, 230, 230, 230, 230, 220, 230, 230, 220 },
+ /* idx=16: 00670 - 0067F */
+ {35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=17: 006D0 - 006DF */
+ {0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 230 },
+ /* idx=18: 006E0 - 006EF */
+ {230, 230, 230, 220, 230, 0, 0, 230, 230, 0, 220, 230, 230, 220, 0, 0 },
+ /* idx=19: 00710 - 0071F */
+ {0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=20: 00730 - 0073F */
+ {230, 220, 230, 230, 220, 230, 230, 220, 220, 220, 230, 220, 220, 230, 220, 230 },
+ /* idx=21: 00740 - 0074F */
+ {230, 230, 220, 230, 220, 230, 220, 230, 220, 230, 230, 0, 0, 0, 0, 0 },
+ /* idx=22: 007E0 - 007EF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230 },
+ /* idx=23: 007F0 - 007FF */
+ {230, 230, 220, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=24: 00810 - 0081F */
+ {0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 230, 230, 230, 230, 230 },
+ /* idx=25: 00820 - 0082F */
+ {230, 230, 230, 230, 0, 230, 230, 230, 0, 230, 230, 230, 230, 230, 0, 0 },
+ /* idx=26: 00850 - 0085F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 0, 0, 0 },
+ /* idx=27: 00930 - 0093F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },
+ /* idx=28: 00940 - 0094F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },
+ /* idx=29: 00950 - 0095F */
+ {0, 230, 220, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=30: 009B0 - 009BF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },
+ /* idx=31: 009C0 - 009CF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },
+ /* idx=32: 00A30 - 00A3F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },
+ /* idx=33: 00A40 - 00A4F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },
+ /* idx=34: 00AB0 - 00ABF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },
+ /* idx=35: 00AC0 - 00ACF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },
+ /* idx=36: 00B30 - 00B3F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },
+ /* idx=37: 00B40 - 00B4F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },
+ /* idx=38: 00BC0 - 00BCF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },
+ /* idx=39: 00C40 - 00C4F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },
+ /* idx=40: 00C50 - 00C5F */
+ {0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=41: 00CB0 - 00CBF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },
+ /* idx=42: 00CC0 - 00CCF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },
+ /* idx=43: 00D40 - 00D4F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },
+ /* idx=44: 00DC0 - 00DCF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0 },
+ /* idx=45: 00E30 - 00E3F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 103, 103, 9, 0, 0, 0, 0, 0 },
+ /* idx=46: 00E40 - 00E4F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 0, 0, 0, 0 },
+ /* idx=47: 00EB0 - 00EBF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 0, 0, 0, 0, 0, 0 },
+ /* idx=48: 00EC0 - 00ECF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 122, 122, 122, 122, 0, 0, 0, 0 },
+ /* idx=49: 00F10 - 00F1F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 0, 0, 0, 0, 0, 0 },
+ /* idx=50: 00F30 - 00F3F */
+ {0, 0, 0, 0, 0, 220, 0, 220, 0, 216, 0, 0, 0, 0, 0, 0 },
+ /* idx=51: 00F70 - 00F7F */
+ {0, 129, 130, 0, 132, 0, 0, 0, 0, 0, 130, 130, 130, 130, 0, 0 },
+ /* idx=52: 00F80 - 00F8F */
+ {130, 0, 230, 230, 9, 0, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=53: 00FC0 - 00FCF */
+ {0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=54: 01030 - 0103F */
+ {0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, 0, 0, 0, 0 },
+ /* idx=55: 01080 - 0108F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0 },
+ /* idx=56: 01350 - 0135F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230 },
+ /* idx=57: 01710 - 0171F */
+ {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=58: 01730 - 0173F */
+ {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=59: 017D0 - 017DF */
+ {0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, 0 },
+ /* idx=60: 018A0 - 018AF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0 },
+ /* idx=61: 01930 - 0193F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 230, 220, 0, 0, 0, 0 },
+ /* idx=62: 01A10 - 01A1F */
+ {0, 0, 0, 0, 0, 0, 0, 230, 220, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=63: 01A60 - 01A6F */
+ {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=64: 01A70 - 01A7F */
+ {0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0, 220 },
+ /* idx=65: 01B30 - 01B3F */
+ {0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=66: 01B40 - 01B4F */
+ {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=67: 01B60 - 01B6F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 230, 230, 230 },
+ /* idx=68: 01B70 - 01B7F */
+ {230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=69: 01BA0 - 01BAF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0 },
+ /* idx=70: 01BE0 - 01BEF */
+ {0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=71: 01BF0 - 01BFF */
+ {0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=72: 01C30 - 01C3F */
+ {0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=73: 01CD0 - 01CDF */
+ {230, 230, 230, 0, 1, 220, 220, 220, 220, 220, 230, 230, 220, 220, 220, 220 },
+ /* idx=74: 01CE0 - 01CEF */
+ {230, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 220, 0, 0 },
+ /* idx=75: 01DC0 - 01DCF */
+ {230, 230, 220, 230, 230, 230, 230, 230, 230, 230, 220, 230, 230, 234, 214, 220 },
+ /* idx=76: 01DD0 - 01DDF */
+ {202, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },
+ /* idx=77: 01DE0 - 01DEF */
+ {230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=78: 01DF0 - 01DFF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 220, 230, 220 },
+ /* idx=79: 020D0 - 020DF */
+ {230, 230, 1, 1, 230, 230, 230, 230, 1, 1, 1, 230, 230, 0, 0, 0 },
+ /* idx=80: 020E0 - 020EF */
+ {0, 230, 0, 0, 0, 1, 1, 230, 220, 230, 1, 1, 220, 220, 220, 220 },
+ /* idx=81: 020F0 - 020FF */
+ {230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=82: 02CE0 - 02CEF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 },
+ /* idx=83: 02CF0 - 02CFF */
+ {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=84: 02D70 - 02D7F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 },
+ /* idx=85: 02DE0 - 02DEF */
+ {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },
+ /* idx=86: 02DF0 - 02DFF */
+ {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },
+ /* idx=87: 03020 - 0302F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 228, 232, 222, 224, 224 },
+ /* idx=88: 03090 - 0309F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0 },
+ /* idx=89: 0A660 - 0A66F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 },
+ /* idx=90: 0A670 - 0A67F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 0, 0 },
+ /* idx=91: 0A6F0 - 0A6FF */
+ {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=92: 0A800 - 0A80F */
+ {0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=93: 0A8C0 - 0A8CF */
+ {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=94: 0A8E0 - 0A8EF */
+ {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },
+ /* idx=95: 0A8F0 - 0A8FF */
+ {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=96: 0A920 - 0A92F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 0 },
+ /* idx=97: 0A950 - 0A95F */
+ {0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=98: 0A9B0 - 0A9BF */
+ {0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=99: 0A9C0 - 0A9CF */
+ {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=100: 0AAB0 - 0AABF */
+ {230, 0, 230, 230, 220, 0, 0, 230, 230, 0, 0, 0, 0, 0, 230, 230 },
+ /* idx=101: 0AAC0 - 0AACF */
+ {0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=102: 0ABE0 - 0ABEF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },
+ /* idx=103: 0FB10 - 0FB1F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0 },
+ /* idx=104: 0FE20 - 0FE2F */
+ {230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=105: 101F0 - 101FF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0 },
+ /* idx=106: 10A00 - 10A0F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 230 },
+ /* idx=107: 10A30 - 10A3F */
+ {0, 0, 0, 0, 0, 0, 0, 0, 230, 1, 220, 0, 0, 0, 0, 9 },
+ /* idx=108: 11040 - 1104F */
+ {0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=109: 110B0 - 110BF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0 },
+ /* idx=110: 1D160 - 1D16F */
+ {0, 0, 0, 0, 0, 216, 216, 1, 1, 1, 0, 0, 0, 226, 216, 216 },
+ /* idx=111: 1D170 - 1D17F */
+ {216, 216, 216, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 220, 220 },
+ /* idx=112: 1D180 - 1D18F */
+ {220, 220, 220, 0, 0, 230, 230, 230, 230, 230, 220, 220, 0, 0, 0, 0 },
+ /* idx=113: 1D1A0 - 1D1AF */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0 },
+ /* idx=114: 1D240 - 1D24F */
+ {0, 0, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+/* The index table to ccc_val[*][16] */
+static const unsigned char ccc_val_index[][16] = {
+ /* idx=0: XXX00 - XXXFF */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=1: 00300 - 003FF */
+ { 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=2: 00400 - 004FF */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=3: 00500 - 005FF */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,10,11,12, 0, 0, 0 },
+ /* idx=4: 00600 - 006FF */
+ { 0,13, 0, 0,14,15, 0,16, 0, 0, 0, 0, 0,17,18, 0 },
+ /* idx=5: 00700 - 007FF */
+ { 0,19, 0,20,21, 0, 0, 0, 0, 0, 0, 0, 0, 0,22,23 },
+ /* idx=6: 00800 - 008FF */
+ { 0,24,25, 0, 0,26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=7: 00900 - 009FF */
+ { 0, 0, 0,27,28,29, 0, 0, 0, 0, 0,30,31, 0, 0, 0 },
+ /* idx=8: 00A00 - 00AFF */
+ { 0, 0, 0,32,33, 0, 0, 0, 0, 0, 0,34,35, 0, 0, 0 },
+ /* idx=9: 00B00 - 00BFF */
+ { 0, 0, 0,36,37, 0, 0, 0, 0, 0, 0, 0,38, 0, 0, 0 },
+ /* idx=10: 00C00 - 00CFF */
+ { 0, 0, 0, 0,39,40, 0, 0, 0, 0, 0,41,42, 0, 0, 0 },
+ /* idx=11: 00D00 - 00DFF */
+ { 0, 0, 0, 0,43, 0, 0, 0, 0, 0, 0, 0,44, 0, 0, 0 },
+ /* idx=12: 00E00 - 00EFF */
+ { 0, 0, 0,45,46, 0, 0, 0, 0, 0, 0,47,48, 0, 0, 0 },
+ /* idx=13: 00F00 - 00FFF */
+ { 0,49, 0,50, 0, 0, 0,51,52, 0, 0, 0,53, 0, 0, 0 },
+ /* idx=14: 01000 - 010FF */
+ { 0, 0, 0,54, 0, 0, 0, 0,55, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=15: 01300 - 013FF */
+ { 0, 0, 0, 0, 0,56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=16: 01700 - 017FF */
+ { 0,57, 0,58, 0, 0, 0, 0, 0, 0, 0, 0, 0,59, 0, 0 },
+ /* idx=17: 01800 - 018FF */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,60, 0, 0, 0, 0, 0 },
+ /* idx=18: 01900 - 019FF */
+ { 0, 0, 0,61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=19: 01A00 - 01AFF */
+ { 0,62, 0, 0, 0, 0,63,64, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=20: 01B00 - 01BFF */
+ { 0, 0, 0,65,66, 0,67,68, 0, 0,69, 0, 0, 0,70,71 },
+ /* idx=21: 01C00 - 01CFF */
+ { 0, 0, 0,72, 0, 0, 0, 0, 0, 0, 0, 0, 0,73,74, 0 },
+ /* idx=22: 01D00 - 01DFF */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,75,76,77,78 },
+ /* idx=23: 02000 - 020FF */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,79,80,81 },
+ /* idx=24: 02C00 - 02CFF */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,82,83 },
+ /* idx=25: 02D00 - 02DFF */
+ { 0, 0, 0, 0, 0, 0, 0,84, 0, 0, 0, 0, 0, 0,85,86 },
+ /* idx=26: 03000 - 030FF */
+ { 0, 0,87, 0, 0, 0, 0, 0, 0,88, 0, 0, 0, 0, 0, 0 },
+ /* idx=27: 0A600 - 0A6FF */
+ { 0, 0, 0, 0, 0, 0,89,90, 0, 0, 0, 0, 0, 0, 0,91 },
+ /* idx=28: 0A800 - 0A8FF */
+ {92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,93, 0,94,95 },
+ /* idx=29: 0A900 - 0A9FF */
+ { 0, 0,96, 0, 0,97, 0, 0, 0, 0, 0,98,99, 0, 0, 0 },
+ /* idx=30: 0AA00 - 0AAFF */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,100,101, 0, 0, 0 },
+ /* idx=31: 0AB00 - 0ABFF */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102, 0 },
+ /* idx=32: 0FB00 - 0FBFF */
+ { 0,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=33: 0FE00 - 0FEFF */
+ { 0, 0,104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=34: 10100 - 101FF */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105 },
+ /* idx=35: 10A00 - 10AFF */
+ {106, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* idx=36: 11000 - 110FF */
+ { 0, 0, 0, 0,108, 0, 0, 0, 0, 0, 0,109, 0, 0, 0, 0 },
+ /* idx=37: 1D100 - 1D1FF */
+ { 0, 0, 0, 0, 0, 0,110,111,112, 0,113, 0, 0, 0, 0, 0 },
+ /* idx=38: 1D200 - 1D2FF */
+ { 0, 0, 0, 0,114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+/* The index table to ccc_val_index[*][16] */
+static const unsigned char ccc_index[] = {
+ 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 0, 0,15, 0, 0, 0,16,
+ 17,18,19,20,21,22, 0, 0,23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,24,25, 0, 0,
+ 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,27, 0,
+ 28,29,30,31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,32, 0, 0,33, 0, 0,34, 0, 0, 0, 0, 0, 0,
+ 0, 0,35, 0, 0, 0, 0, 0,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,37,38,};
+
+#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */
diff -r 875d4ea72349 -r f03cc5a9c894 head/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c Fri Mar 02 16:59:15 2012 +0200
@@ -0,0 +1,338 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_bzip2.c 201091 2009-12-28 02:22:41Z kientzle $");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_BZLIB_H
+#include <bzlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_write_set_compression_bzip2(struct archive *a)
+{
+ __archive_write_filters_free(a);
+ return (archive_write_add_filter_bzip2(a));
+}
+#endif
+
+#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
+int
+archive_write_add_filter_bzip2(struct archive *a)
+{
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "bzip2 compression not supported on this platform");
+ return (ARCHIVE_FATAL);
+}
+#else
+/* Don't compile this if we don't have bzlib. */
+
+struct private_data {
+ int compression_level;
+ bz_stream stream;
+ int64_t total_in;
+ char *compressed;
+ size_t compressed_buffer_size;
+};
+
+/*
+ * Yuck. bzlib.h is not const-correct, so I need this one bit
+ * of ugly hackery to convert a const * pointer to a non-const pointer.
+ */
+#define SET_NEXT_IN(st,src) \
+ (st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
+
+static in