[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