[Cmake-commits] CMake branch, next, updated. v2.8.7-1966-gccfe520

Brad King brad.king at kitware.com
Thu Jan 5 09:20:25 EST 2012


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, next has been updated
       via  ccfe52012ac0df9baad45aa567dabd223feff580 (commit)
       via  6c611c6b94ef54cbfdc81a1f049032f13a0ef024 (commit)
       via  2f5b677186615c0626b3670afdc4bddec8fbf17e (commit)
       via  156cb3bbf257f747672eac945fa2e19d33fc3a63 (commit)
       via  fd42bf1bdcb95615dd725ae588db02b22a3aebaa (commit)
       via  4f4fe6e50bb3dbe59f9bc3cc848cbd07dead324d (commit)
      from  2544436687e1742125b450255eedc09e92a46549 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ccfe52012ac0df9baad45aa567dabd223feff580
commit ccfe52012ac0df9baad45aa567dabd223feff580
Merge: 2544436 6c611c6
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jan 5 09:20:09 2012 -0500
Commit:     CMake Topic Stage <kwrobot at kitware.com>
CommitDate: Thu Jan 5 09:20:09 2012 -0500

    Merge topic 'update-libarchive' into next
    
    6c611c6 libarchive: Restore CMake 2.6.3 as minimum version
    2f5b677 libarchive: Update README-CMake.txt for new snapshot
    156cb3b Merge branch 'libarchive-upstream' into update-libarchive
    fd42bf1 libarchive: Set .gitattributes to allow trailing whitespace
    4f4fe6e libarchive 3.0.2-r4051 (reduced)


http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6c611c6b94ef54cbfdc81a1f049032f13a0ef024
commit 6c611c6b94ef54cbfdc81a1f049032f13a0ef024
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jan 5 09:09:31 2012 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 5 09:09:31 2012 -0500

    libarchive: Restore CMake 2.6.3 as minimum version
    
    Upstream libarchive now requires CMake 2.8 to get the newer add_test
    functionality.  Since we do not build libarchive's tests we do not
    need the requirement.

diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt
index ebf28ae..7f7a69f 100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@ -2,7 +2,7 @@
 #
 PROJECT(libarchive C)
 #
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3 FATAL_ERROR)
 SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")
 if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
   set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${libarchive_BINARY_DIR}/bin)

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2f5b677186615c0626b3670afdc4bddec8fbf17e
commit 2f5b677186615c0626b3670afdc4bddec8fbf17e
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jan 5 09:06:42 2012 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 5 09:06:42 2012 -0500

    libarchive: Update README-CMake.txt for new snapshot

diff --git a/Utilities/cmlibarchive/README-CMake.txt b/Utilities/cmlibarchive/README-CMake.txt
index bbd9e8b..45cb093 100644
--- a/Utilities/cmlibarchive/README-CMake.txt
+++ b/Utilities/cmlibarchive/README-CMake.txt
@@ -11,7 +11,7 @@ branch, but it is merged into our history.
 Update libarchive from upstream as follows.  Create a local branch to
 explicitly reference the upstream snapshot branch head:
 
- git branch libarchive-upstream 2f4a3792
+ git branch libarchive-upstream 4f4fe6e5
 
 Use a temporary directory to checkout the branch:
 
@@ -24,7 +24,7 @@ Use a temporary directory to checkout the branch:
 Now place the (reduced) libarchive content in this directory.  See
 instructions shown by
 
- git log 2f4a3792
+ git log 4f4fe6e5
 
 for help extracting the content from the upstream svn repo.  Then run
 the following commands to commit the new version.  Substitute the
@@ -34,8 +34,8 @@ appropriate date and version number:
 
  GIT_AUTHOR_NAME='LibArchive Upstream' \
  GIT_AUTHOR_EMAIL='libarchive-discuss at googlegroups.com' \
- GIT_AUTHOR_DATE='2011-12-19 18:30:59 -0500' \
- git commit -m 'libarchive 3.0.1-r3950 (reduced)' &&
+ GIT_AUTHOR_DATE='2011-12-31 13:54:34 -0500' \
+ git commit -m 'libarchive 3.0.2-r4051 (reduced)' &&
  git commit --amend
 
 Edit the commit message to describe the procedure used to obtain the

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=156cb3bbf257f747672eac945fa2e19d33fc3a63
commit 156cb3bbf257f747672eac945fa2e19d33fc3a63
Merge: fd42bf1 4f4fe6e
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jan 5 09:02:58 2012 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 5 09:02:58 2012 -0500

    Merge branch 'libarchive-upstream' into update-libarchive
    
    Conflicts:
    	Utilities/cmlibarchive/CMakeLists.txt
    	Utilities/cmlibarchive/libarchive/archive_windows.c

diff --cc Utilities/cmlibarchive/CMakeLists.txt
index d0460ec,0000000..ebf28ae
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@@ -1,1117 -1,0 +1,1114 @@@
 +#
 +#
 +PROJECT(libarchive C)
 +#
- CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3 FATAL_ERROR)
++CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
 +SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")
 +if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
 +  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${libarchive_BINARY_DIR}/bin)
 +endif()
 +
 +# On MacOS, prefer MacPorts libraries to system libraries.
 +# I haven't come up with a compelling argument for this to be conditional.
 +list(APPEND CMAKE_PREFIX_PATH /opt/local)
 +
 +#
 +# Version - read from 'version' file.
 +#
 +FILE(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/build/version _version)
 +STRING(REGEX REPLACE
 + "^([0-9])[0-9][0-9][0-9][0-9][0-9][0-9][a-z]?$" "\\1" _major ${_version})
 +STRING(REGEX REPLACE
 + "^[0-9]([0-9][0-9][0-9])[0-9][0-9][0-9][a-z]?$" "\\1" _minor ${_version})
 +STRING(REGEX REPLACE
 + "^[0-9][0-9][0-9][0-9]([0-9][0-9][0-9])[a-z]?$" "\\1" _revision ${_version})
 +STRING(REGEX REPLACE
 + "^[0-9][0-9][0-9][0-9][0-9][0-9][0-9]([a-z]?)$" "\\1" _quality ${_version})
 +SET(_version_number ${_major}${_minor}${_revision})
 +STRING(REGEX REPLACE "[0]*([^0]*[0-9])$" "\\1" _trimmed_minor ${_minor})
 +STRING(REGEX REPLACE "[0]*([^0]*[0-9])$" "\\1" _trimmed_revision ${_revision})
 +#
 +SET(VERSION                    "${_major}.${_trimmed_minor}.${_trimmed_revision}${_quality}")
 +SET(BSDCPIO_VERSION_STRING     "${VERSION}")
 +SET(BSDTAR_VERSION_STRING      "${VERSION}")
 +SET(LIBARCHIVE_VERSION_NUMBER  "${_version_number}")
 +SET(LIBARCHIVE_VERSION_STRING  "${VERSION}")
 +
 +# INTERFACE_VERSION increments with every release
 +# libarchive 2.7 == interface version 9 = 2 + 7 
 +# libarchive 2.8 == interface version 10 = 2 + 8
- # libarchive 3.0 == interface version 11
- # libarchive 3.x == interface version 11 + x
- math(EXPR INTERFACE_VERSION  "11 + ${_minor}")
++# libarchive 2.9 == interface version 11 = 2 + 9
++# libarchive 3.0 == interface version 12
++# libarchive 3.x == interface version 12 + x
++math(EXPR INTERFACE_VERSION  "12 + ${_minor}")
 +
 +# Set SOVERSION == Interface version
 +# ?? Should there be more here ??
 +SET(SOVERSION "${INTERFACE_VERSION}")
 +
 +# Disable warnings to avoid changing 3rd party code.
 +IF("${CMAKE_C_COMPILER_ID}" MATCHES
 +    "^(GNU|Clang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
 +  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 +ELSEIF("${CMAKE_C_COMPILER_ID}" MATCHES "^(PathScale)$")
 +  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
 +ELSEIF(BORLAND)
 +  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-")
 +ENDIF()
 +
 +# Enable CTest/CDash support
 +include(CTest)
 +
- # Provide ADD_TEST_28 macro to approximate CMake 2.8 ADD_TEST(NAME).
- # TODO: Require CMake 2.8 and drop this workaround (perhaps late 2010).
- INCLUDE(AddTest28)
- 
 +OPTION(ENABLE_NETTLE "Enable use of Nettle" ON)
 +OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON)
 +OPTION(ENABLE_XATTR "Enable extended attribute support" ON)
 +OPTION(ENABLE_ACL "Enable ACL support" ON)
 +OPTION(ENABLE_ICONV "Enable iconv support" ON)
 +
 +IF(WIN32)
 +  IF(MSVC60)
 +    SET(WINVER 0x0400)
 +  ELSE()
 +    SET(WINVER 0x0500)
 +  ENDIF()
 +  SET(_WIN32_WINNT ${WINVER})
 +ENDIF(WIN32)
 +
 +IF("${CMAKE_C_PLATFORM_ID}" MATCHES "^(HP-UX)$")
 +  ADD_DEFINITIONS(-D_XOPEN_SOURCE=500) # Ask wchar.h for mbstate_t
 +ENDIF()
 +
 +#
 +INCLUDE(CheckCSourceCompiles)
 +INCLUDE(CheckCSourceRuns)
 +INCLUDE(CheckFileOffsetBits)
 +INCLUDE(CheckFuncs)
 +INCLUDE(CheckHeaderDirent)
 +INCLUDE(CheckIncludeFile)
 +INCLUDE(CheckIncludeFiles)
 +INCLUDE(CheckLibraryExists)
 +INCLUDE(CheckStructMember)
 +INCLUDE(CheckSymbolExists)
 +INCLUDE(CheckTypeExists)
 +INCLUDE(CheckTypeSize)
 +
 +#
 +# Generate list.h
 +#
 +MACRO (GENERATE_LIST_H _listfile _cmlist __list_sources)
 +  SET(_argv ${ARGV})
 +  # Remove _listfile and _cmlist from _argv
 +  LIST(REMOVE_AT _argv 0 1)
 +  IF (NOT EXISTS "${_listfile}" OR
 +     ${_cmlist} IS_NEWER_THAN "${_listfile}")
 +
 +    MESSAGE(STATUS "Generating ${_listfile}")
 +    FILE(WRITE ${_listfile} "")
 +    FOREACH (testfile ${_argv})
 +      IF (testfile MATCHES "^test_[^/]+[.]c$")
 +        FILE(STRINGS ${testfile} testvar REGEX "^DEFINE_TEST")
 +        FOREACH (deftest ${testvar})
 +          FILE(APPEND ${_listfile} "${deftest}\n")
 +        ENDFOREACH (deftest)
 +      ENDIF (testfile MATCHES "^test_[^/]+[.]c$")
 +    ENDFOREACH (testfile)
 +
 +  ENDIF (NOT EXISTS "${_listfile}" OR
 +     ${_cmlist} IS_NEWER_THAN "${_listfile}")
 +ENDMACRO (GENERATE_LIST_H)
 +#
 +# Generate installation rules for man pages.
 +#
 +MACRO (INSTALL_MAN __mans)
 +  FOREACH (_man ${ARGV})
 +    STRING(REGEX REPLACE "^.+[.]([1-9])" "\\1" _mansect ${_man})
 +    INSTALL(FILES ${_man} DESTINATION "share/man/man${_mansect}")
 +  ENDFOREACH (_man)
 +ENDMACRO (INSTALL_MAN __mans)
 +
 +#
 +# Check compress/decompress libraries
 +#
 +IF(WIN32 AND NOT CMAKE_CL_64 AND NOT CYGWIN)
 +  # GnuWin32 is only for Win32, not Win64.
 +  SET(__GNUWIN32PATH "C:/Program Files/GnuWin32")
 +ENDIF(WIN32 AND NOT CMAKE_CL_64 AND NOT CYGWIN)
 +IF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}")
 +  # You have to add a path availabel DLL file into PATH environment variable.
 +  # Maybe DLL path is "C:/Program Files/GnuWin32/bin".
 +  # The zlib and the bzip2 Setup program have installed programs and DLLs into
 +  # "C:/Program Files/GnuWin32" by default.
 +  # This is convenience setting for Windows.
 +  SET(CMAKE_PREFIX_PATH ${__GNUWIN32PATH} $(CMAKE_PREFIX_PATH))
 +  #
 +  # If you didn't use Setup program or installed into nonstandard path,
 +  # cmake cannot find out your zlib or bzip2 libraries and include files,
 +  # you should execute cmake with  -DCMAKE_PREFIX_PATH option.
 +  #   e.g.
 +  #     cmake -DCMAKE_PREFIX_PATH=<your-GnuWin32-path> <path-to-source>
 +  #
 +  # If compiling error occured in zconf.h, You may need patch to zconf.h.
 +  #--- zconf.h.orig	2005-07-21 00:40:26.000000000
 +  #+++ zconf.h	2009-01-19 11:39:10.093750000
 +  #@@ -286,7 +286,7 @@
 +  # 
 +  # #if 1           /* HAVE_UNISTD_H -- this line is updated by ./configure */
 +  # #  include <sys/types.h> /* for off_t */
 +  #-#  include <unistd.h>    /* for SEEK_* and off_t */
 +  #+#  include <stdio.h>    /* for SEEK_* and off_t */
 +  # #  ifdef VMS
 +  # #    include <unixio.h>   /* for off_t */
 +  # #  endif
 +ENDIF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}")
 +
 +SET(ADDITIONAL_LIBS "")
 +#
 +# Find ZLIB
 +#
 +FIND_PACKAGE(ZLIB)
 +IF(ZLIB_FOUND)
 +  SET(HAVE_LIBZ 1)
 +  SET(HAVE_ZLIB_H 1)
 +  INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
 +  LIST(APPEND ADDITIONAL_LIBS ${ZLIB_LIBRARIES})
 +  IF(WIN32 AND NOT CYGWIN)
 +    SET(CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIR})
 +    SET(CMAKE_REQUIRED_LIBRARIES ${ZLIB_LIBRARIES})
 +    CHECK_C_SOURCE_Runs(
 +      "#ifndef ZLIB_WINAPI\n#define ZLIB_WINAPI\n#endif\n#include <zlib.h>\nint main() {uLong f = zlibCompileFlags(); return (f&(1U<<10))?0:-1; }"
 +      ZLIB_WINAPI)
 +    SET(CMAKE_REQUIRED_INCLUDES)
 +    SET(CMAKE_REQUIRED_LIBRARIES)
 +  ENDIF(WIN32 AND NOT CYGWIN)
 +ELSE(ZLIB_FOUND)
 +  MESSAGE(FATAL_ERROR "CMake requires zlib to be available to libarchive")
 +ENDIF(ZLIB_FOUND)
 +#
 +# Find BZip2
 +#
 +FIND_PACKAGE(BZip2)
 +IF(BZIP2_FOUND)
 +  SET(HAVE_LIBBZ2 1)
 +  SET(HAVE_BZLIB_H 1)
 +  INCLUDE_DIRECTORIES(${BZIP2_INCLUDE_DIR})
 +  LIST(APPEND ADDITIONAL_LIBS ${BZIP2_LIBRARIES})
 +ENDIF(BZIP2_FOUND)
 +MARK_AS_ADVANCED(CLEAR BZIP2_INCLUDE_DIR)
 +MARK_AS_ADVANCED(CLEAR BZIP2_LIBRARY)
 +
 +IF(0) # CMake does not need LZMA support in libarchive
 +#
 +# Find LZMA
 +#
 +FIND_PACKAGE(LZMA)
 +IF(LZMA_FOUND)
 +  SET(HAVE_LIBLZMA 1)
 +  SET(HAVE_LZMA_H 1)
 +  INCLUDE_DIRECTORIES(${LZMA_INCLUDE_DIR})
 +  LIST(APPEND ADDITIONAL_LIBS ${LZMA_LIBRARIES})
 +ELSEIF(LZMADEC_FOUND)
 +  SET(HAVE_LIBLZMADEC 1)
 +  SET(HAVE_LZMADEC_H 1)
 +  INCLUDE_DIRECTORIES(${LZMADEC_INCLUDE_DIR})
 +  LIST(APPEND ADDITIONAL_LIBS ${LZMADEC_LIBRARIES})
 +ENDIF(LZMA_FOUND)
 +ENDIF()
 +
 +#
 +# Check headers
 +#
 +CHECK_HEADER_DIRENT()
 +
 +SET(INCLUDES "")
 +MACRO (LA_CHECK_INCLUDE_FILE header var)
 +      CHECK_INCLUDE_FILES("${INCLUDES};${header}" ${var})
 +      IF (${var})
 +      	 SET(INCLUDES ${INCLUDES} ${header})
 +      ENDIF (${var})
 +ENDMACRO (LA_CHECK_INCLUDE_FILE)
 +
 +# Some FreeBSD headers assume sys/types.h was already included.
 +LA_CHECK_INCLUDE_FILE("sys/types.h" HAVE_SYS_TYPES_H)
 +
 +# Alphabetize the rest unless there's a compelling reason
 +LA_CHECK_INCLUDE_FILE("acl/libacl.h" HAVE_ACL_LIBACL_H)
 +LA_CHECK_INCLUDE_FILE("ctype.h" HAVE_CTYPE_H)
 +LA_CHECK_INCLUDE_FILE("copyfile.h" HAVE_COPYFILE_H)
 +LA_CHECK_INCLUDE_FILE("direct.h" HAVE_DIRECT_H)
 +LA_CHECK_INCLUDE_FILE("dlfcn.h" HAVE_DLFCN_H)
 +LA_CHECK_INCLUDE_FILE("errno.h" HAVE_ERRNO_H)
 +LA_CHECK_INCLUDE_FILE("ext2fs/ext2_fs.h" HAVE_EXT2FS_EXT2_FS_H)
 +
 +CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
 +#include <ext2fs/ext2_fs.h>
 +int main(void) { return EXT2_IOC_GETFLAGS; }" HAVE_WORKING_EXT2_IOC_GETFLAGS)
 +
 +LA_CHECK_INCLUDE_FILE("fcntl.h" HAVE_FCNTL_H)
 +LA_CHECK_INCLUDE_FILE("grp.h" HAVE_GRP_H)
 +LA_CHECK_INCLUDE_FILE("inttypes.h" HAVE_INTTYPES_H)
 +LA_CHECK_INCLUDE_FILE("io.h" HAVE_IO_H)
 +LA_CHECK_INCLUDE_FILE("langinfo.h" HAVE_LANGINFO_H)
 +LA_CHECK_INCLUDE_FILE("limits.h" HAVE_LIMITS_H)
 +LA_CHECK_INCLUDE_FILE("linux/types.h" HAVE_LINUX_TYPES_H)
 +LA_CHECK_INCLUDE_FILE("linux/fiemap.h" HAVE_LINUX_FIEMAP_H)
 +LA_CHECK_INCLUDE_FILE("linux/fs.h" HAVE_LINUX_FS_H)
 +LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H)
 +LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H)
 +LA_CHECK_INCLUDE_FILE("memory.h" HAVE_MEMORY_H)
 +LA_CHECK_INCLUDE_FILE("paths.h" HAVE_PATHS_H)
 +LA_CHECK_INCLUDE_FILE("poll.h" HAVE_POLL_H)
 +LA_CHECK_INCLUDE_FILE("process.h" HAVE_PROCESS_H)
 +LA_CHECK_INCLUDE_FILE("pwd.h" HAVE_PWD_H)
 +LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
 +LA_CHECK_INCLUDE_FILE("signal.h" HAVE_SIGNAL_H)
 +LA_CHECK_INCLUDE_FILE("stdarg.h" HAVE_STDARG_H)
 +LA_CHECK_INCLUDE_FILE("stdint.h" HAVE_STDINT_H)
 +LA_CHECK_INCLUDE_FILE("stdlib.h" HAVE_STDLIB_H)
 +LA_CHECK_INCLUDE_FILE("string.h" HAVE_STRING_H)
 +LA_CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H)
 +LA_CHECK_INCLUDE_FILE("sys/acl.h" HAVE_SYS_ACL_H)
 +LA_CHECK_INCLUDE_FILE("sys/cdefs.h" HAVE_SYS_CDEFS_H)
 +LA_CHECK_INCLUDE_FILE("sys/ioctl.h" HAVE_SYS_IOCTL_H)
 +LA_CHECK_INCLUDE_FILE("sys/mkdev.h" HAVE_SYS_MKDEV_H)
 +LA_CHECK_INCLUDE_FILE("sys/mount.h" HAVE_SYS_MOUNT_H)
 +LA_CHECK_INCLUDE_FILE("sys/param.h" HAVE_SYS_PARAM_H)
 +LA_CHECK_INCLUDE_FILE("sys/poll.h" HAVE_SYS_POLL_H)
 +LA_CHECK_INCLUDE_FILE("sys/select.h" HAVE_SYS_SELECT_H)
 +LA_CHECK_INCLUDE_FILE("sys/stat.h" HAVE_SYS_STAT_H)
 +LA_CHECK_INCLUDE_FILE("sys/statfs.h" HAVE_SYS_STATFS_H)
 +LA_CHECK_INCLUDE_FILE("sys/statvfs.h" HAVE_SYS_STATVFS_H)
 +LA_CHECK_INCLUDE_FILE("sys/time.h" HAVE_SYS_TIME_H)
 +LA_CHECK_INCLUDE_FILE("sys/utime.h" HAVE_SYS_UTIME_H)
 +LA_CHECK_INCLUDE_FILE("sys/utsname.h" HAVE_SYS_UTSNAME_H)
 +LA_CHECK_INCLUDE_FILE("sys/vfs.h" HAVE_SYS_VFS_H)
 +LA_CHECK_INCLUDE_FILE("sys/wait.h" HAVE_SYS_WAIT_H)
 +LA_CHECK_INCLUDE_FILE("time.h" HAVE_TIME_H)
 +LA_CHECK_INCLUDE_FILE("unistd.h" HAVE_UNISTD_H)
 +LA_CHECK_INCLUDE_FILE("utime.h" HAVE_UTIME_H)
 +LA_CHECK_INCLUDE_FILE("wchar.h" HAVE_WCHAR_H)
 +LA_CHECK_INCLUDE_FILE("wctype.h" HAVE_WCTYPE_H)
 +LA_CHECK_INCLUDE_FILE("windows.h" HAVE_WINDOWS_H)
 +# Following files need windwos.h, so we should test it after windows.h test.
 +LA_CHECK_INCLUDE_FILE("wincrypt.h" HAVE_WINCRYPT_H)
 +LA_CHECK_INCLUDE_FILE("winioctl.h" HAVE_WINIOCTL_H)
 +
 +#
 +# Check whether use of __EXTENSIONS__ is safe.
 +# We need some macro such as _GNU_SOURCE to use extension functions.
 +#
 +SET(_INCLUDE_FILES)
 +FOREACH (it ${_HEADER})
 +   SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n")
 +ENDFOREACH (it)
 +
 +CHECK_C_SOURCE_COMPILES(
 +  "#define __EXTENSIONS__ 1
 +   ${_INCLUDE_FILES}
 +   int main() { return 0;}"
 + SAFE_TO_DEFINE_EXTENSIONS)
 +
 +#
 +# Find Nettle
 +#
 +IF(ENABLE_NETTLE)
 +  CHECK_LIBRARY_EXISTS(nettle "nettle_sha1_digest" "" NETTLE_FOUND)
 +  IF(NETTLE_FOUND)
 +    SET(CMAKE_REQUIRED_LIBRARIES "nettle")
 +    FIND_LIBRARY(NETTLE_LIBRARY NAMES nettle)
 +    LIST(APPEND ADDITIONAL_LIBS ${NETTLE_LIBRARY})
 +  ELSE(NETTLE_FOUND)
 +    SET(ENABLE_NETTLE OFF)
 +  ENDIF(NETTLE_FOUND)
 +ENDIF(ENABLE_NETTLE)
 +
 +#
 +# Find OpenSSL
 +# (Except on Mac, where OpenSSL is deprecated.)
 +#
 +IF(ENABLE_OPENSSL AND NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
 +  FIND_PACKAGE(OpenSSL)
 +ELSE()
 +  SET(OPENSSL_FOUND FALSE) # Override cached value
 +ENDIF()
 +
 +# FreeBSD libmd
 +CHECK_LIBRARY_EXISTS(md "MD5Init" "" LIBMD_FOUND)
 +IF(LIBMD_FOUND)
 +  SET(CMAKE_REQUIRED_LIBRARIES "md")
 +  FIND_LIBRARY(LIBMD_LIBRARY NAMES md)
 +  LIST(APPEND ADDITIONAL_LIBS ${LIBMD_LIBRARY})
 +ENDIF(LIBMD_FOUND)
 +
 +#
 +# How to prove that CRYPTO functions, which have several names on various
 +# platforms, just see if archive_crypto.c can compile and link against
 +# required libraries.
 +#
 +MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 +    IF(HAVE_SYS_TYPES_H)
 +        SET(CRYPTO_HEADER_CONFIG "#define HAVE_SYS_TYPES_H 1\n")
 +    ELSE(HAVE_SYS_TYPES_H)
 +        SET(CRYPTO_HEADER_CONFIG "")
 +    ENDIF(HAVE_SYS_TYPES_H)
 +
 +    FOREACH(ALGORITHM ${ALGORITHMS})
 +      STRING(TOLOWER "${ALGORITHM}" lower_algorithm)
 +      STRING(TOUPPER "${ALGORITHM}" algorithm)
 +      IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND NOT OPENSSL_FOUND)
 +        SET(ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} FALSE)
 +      ELSEIF("${IMPLEMENTATION}" MATCHES "^NETTLE$" AND NOT NETTLE_FOUND)
 +        SET(ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} FALSE)
 +      ENDIF("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND NOT OPENSSL_FOUND)
 +
 +      IF(NOT DEFINED ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +        # Probe the local implementation for whether this
 +	# crypto implementation is available on this platform.
 +	SET(TRY_CRYPTO_REQUIRED_INCLUDES
 +	  "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_CURRENT_SOURCE_DIR}/libarchive;${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
 +	SET(TRY_CRYPTO_REQUIRED_LIBS)
 +	IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 +	    SET(TRY_CRYPTO_REQUIRED_INCLUDES
 +	      "${TRY_CRYPTO_REQUIRED_INCLUDES};${OPENSSL_INCLUDE_DIR}")
 +	    SET(TRY_CRYPTO_REQUIRED_LIBS
 +	        "-DLINK_LIBRARIES:STRING=${OPENSSL_LIBRARIES}")
 +	ELSEIF("${IMPLEMENTATION}" MATCHES "^NETTLE$" AND NETTLE_FOUND)
 +	    SET(TRY_CRYPTO_REQUIRED_LIBS
 +	        "-DLINK_LIBRARIES:STRING=${NETTLE_LIBRARY}")
 +	ELSEIF("${IMPLEMENTATION}" MATCHES "^LIBMD$" AND LIBMD_FOUND)
 +	    SET(TRY_CRYPTO_REQUIRED_LIBS
 +	        "-DLINK_LIBRARIES:STRING=${LIBMD_LIBRARY}")
 +	ENDIF("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 +
 +	FILE(READ "${CMAKE_CURRENT_SOURCE_DIR}/libarchive/archive_crypto.c"
 +	     ARCHIVE_CRYPTO_C)
 +
 +	SET(SOURCE "
 +#define ARCHIVE_${algorithm}_COMPILE_TEST
 +#define ARCHIVE_CRYPTO_${algorithm}_${IMPLEMENTATION}
 +#define PLATFORM_CONFIG_H \"check_crypto_md.h\"
 +
 +${ARCHIVE_CRYPTO_C}
 +
 +int
 +main(int argc, char **argv)
 +{
 +  archive_${lower_crypto}_ctx ctx;
 +  archive_${lower_crypto}_init(&ctx);
 +  archive_${lower_crypto}_update(&ctx, *argv, argc);
 +  archive_${lower_crypto}_final(&ctx, NULL);
 +  return 0;
 +}
 +")
 +
 +  FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.h" "")
 +	FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c" "${SOURCE}")
 +	MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION}")
 +
 +	TRY_COMPILE(ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION}
 +	  ${CMAKE_BINARY_DIR}
 +	  ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c
 +	  CMAKE_FLAGS
 +	   "${TRY_CRYPTO_REQUIRED_LIBS}"
 +	   "${TRY_CRYPTO_REQUIRED_INCLUDES}"
 +	  OUTPUT_VARIABLE OUTPUT)
 +
 +	# Inform user whether or not we found it; if not, log why we didn't.
 +        IF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +          MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} -- found")
 +        ELSE (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +          MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} -- not found")
 +          FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
 +    	    "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} failed with the following output:\n"
 +    	    "${OUTPUT}\n"
 +    	    "Source file was:\n${SOURCE}\n")
 +        ENDIF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +      ENDIF(NOT DEFINED ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +
 +      # Add appropriate libs/includes depending on whether the implementation
 +      # was found on this platform.
 +      IF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +        IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 +          INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
 +	  LIST(APPEND ADDITIONAL_LIBS ${OPENSSL_LIBRARIES})
 +	   LIST(REMOVE_DUPLICATES ADDITIONAL_LIBS)
 +        ENDIF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 +      ENDIF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +    ENDFOREACH(ALGORITHM ${ALGORITHMS})
 +ENDMACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 +
 +#
 +# CRYPTO functions on Windows is defined at archive_windows.c, thus we do not
 +# need the test what the functions can be mapped to archive_{crypto name}_init,
 +# archive_{crypto name}_update and archive_{crypto name}_final.
 +# The functions on Windows use CALG_{crypto name} macro to create a crypt object
 +# and then we need to know what CALG_{crypto name} macros is available to show
 +# ARCHIVE_CRYPTO_{crypto name}_WIN macros because Windows 2000 and earlier version
 +# of Windows XP do not support SHA256, SHA384 and SHA512.
 +#
 +MACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
 +  IF(WIN32 AND NOT CYGWIN)
 +    FOREACH(CRYPTO ${CRYPTO_LIST})
 +      IF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 +	STRING(TOUPPER "${CRYPTO}" crypto)
 +	SET(ALGID "")
 +	IF ("${CRYPTO}" MATCHES "^MD5$")
 +	    SET(ALGID "CALG_MD5")
 +	ENDIF ("${CRYPTO}" MATCHES "^MD5$")
 +	IF ("${CRYPTO}" MATCHES "^SHA1$")
 +	    SET(ALGID "CALG_SHA1")
 +	ENDIF ("${CRYPTO}" MATCHES "^SHA1$")
 +	IF ("${CRYPTO}" MATCHES "^SHA256$")
 +	    SET(ALGID "CALG_SHA_256")
 +	ENDIF ("${CRYPTO}" MATCHES "^SHA256$")
 +	IF ("${CRYPTO}" MATCHES "^SHA384$")
 +	    SET(ALGID "CALG_SHA_384")
 +	ENDIF ("${CRYPTO}" MATCHES "^SHA384$")
 +	IF ("${CRYPTO}" MATCHES "^SHA512$")
 +	    SET(ALGID "CALG_SHA_512")
 +	ENDIF ("${CRYPTO}" MATCHES "^SHA512$")
 +
 +	SET(SOURCE "#define ${crypto}_COMPILE_TEST
 +#define _WIN32_WINNT ${_WIN32_WINNT}
 +#define WINVER ${WINVER}
 +#include <windows.h>
 +#include <wincrypt.h>
 +
 +int
 +main(int argc, char **argv)
 +{
 +	return ${ALGID};
 +}
 +")
 +	SET(SOURCE_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_win.c")
 +
 +	FILE(WRITE "${SOURCE_FILE}" "${SOURCE}")
 +	MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN")
 +
 +	TRY_COMPILE(ARCHIVE_CRYPTO_${CRYPTO}_WIN
 +	  ${CMAKE_BINARY_DIR}
 +	  ${SOURCE_FILE}
 +	  CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_CURRENT_SOURCE_DIR}/libarchive"
 +	  OUTPUT_VARIABLE OUTPUT)
 +
 +	IF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 +	    MESSAGE(STATUS
 +	        "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- found")
 +	ELSE (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 +	    MESSAGE(STATUS
 +	         "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- not found")
 +    	    FILE(APPEND
 +	        ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
 +                "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN failed with the following output:\n"
 +        	"${OUTPUT}\n"
 +        	"Source file was:\n${SOURCE}\n")
 +	ENDIF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 +
 +      ENDIF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 +    ENDFOREACH(CRYPTO)
 +  ENDIF(WIN32 AND NOT CYGWIN)
 +ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
 +
 +#
 +# Find iconv
 +# POSIX defines the second arg as const char **
 +# and requires it to be in libc.  But we can accept
 +# a non-const argument here and can support iconv()
 +# being in libiconv.
 +#
 +MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
 +  IF(NOT HAVE_ICONV)
 +    CHECK_C_SOURCE_COMPILES(
 +      "#include <stdlib.h>
 +       #include <iconv.h>
 +       int main() {
 +          ${TRY_ICONV_CONST} char *ccp;
 +          iconv_t cd = iconv_open(\"\", \"\");
 +          iconv(cd, &ccp, (size_t *)0, (char **)0, (size_t *)0);
 +          iconv_close(cd);
 +          return 0;
 +       }"
 +     HAVE_ICONV_${LIB}_${TRY_ICONV_CONST})
 +    IF(HAVE_ICONV_${LIB}_${TRY_ICONV_CONST})
 +      SET(HAVE_ICONV true)
 +      SET(ICONV_CONST ${TRY_ICONV_CONST})
 +    ENDIF(HAVE_ICONV_${LIB}_${TRY_ICONV_CONST})
 +  ENDIF(NOT HAVE_ICONV)
 +ENDMACRO(CHECK_ICONV TRY_ICONV_CONST)
 +
 +IF(ENABLE_ICONV)
 +  FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
 +  MARK_AS_ADVANCED(ICONV_INCLUDE_DIR)
 +  IF(ICONV_INCLUDE_DIR)
 +    #SET(INCLUDES ${INCLUDES} "iconv.h")
 +    SET(HAVE_ICONV_H 1)
 +    INCLUDE_DIRECTORIES(${ICONV_INCLUDE_DIR})
 +    SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
 +    CHECK_ICONV("libc" "const")
 +    CHECK_ICONV("libc" "")
 +
 +    # If iconv isn't in libc and we have a libiconv, try that.
 +    FIND_LIBRARY(LIBICONV_PATH iconv)
 +    IF(NOT HAVE_ICONV AND LIBICONV_PATH)
 +      LIST(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBICONV_PATH})
 +      CHECK_ICONV("libiconv" "const")
 +      CHECK_ICONV("libiconv" "")
 +      IF (HAVE_ICONV)
 +        LIST(APPEND ADDITIONAL_LIBS ${LIBICONV_PATH})
 +      ENDIF(HAVE_ICONV)
 +    ENDIF(NOT HAVE_ICONV AND LIBICONV_PATH)
 +  ENDIF(ICONV_INCLUDE_DIR)
 +  #
 +  # Find locale_charset() for libiconv.
 +  #
 +  IF(LIBICONV_PATH)
 +    CHECK_INCLUDE_FILES("localcharset.h" HAVE_LOCALCHARSET_H)
 +    CHECK_FUNCTION_EXISTS_GLIBC(locale_charset HAVE_LOCALE_CHARSET)
 +    IF(NOT HAVE_LOCALE_CHARSET)
 +      FIND_LIBRARY(LIBCHARSET_PATH charset)
 +      IF(LIBCHARSET_PATH)
 +        SET(CMAKE_REQUIRED_LIBRARIES ${LIBCHARSET_PATH})
 +        CHECK_FUNCTION_EXISTS_GLIBC(locale_charset HAVE_LOCALE_CHARSET)
 +        IF(HAVE_LOCALE_CHARSET)
 +          LIST(APPEND ADDITIONAL_LIBS ${LIBCHARSET_PATH})
 +        ENDIF(HAVE_LOCALE_CHARSET)
 +      ENDIF(LIBCHARSET_PATH)
 +    ENDIF(NOT HAVE_LOCALE_CHARSET)
 +  ENDIF(LIBICONV_PATH)
 +ELSE(ENABLE_ICONV)
 +  # Make sure ICONV variables are not in CACHE after ENABLE_ICONV disabled
 +  # (once enabled).
 +  UNSET(HAVE_LOCALE_CHARSET CACHE)
 +  UNSET(HAVE_ICONV CACHE)
 +  UNSET(HAVE_ICONV_libc_ CACHE)
 +  UNSET(HAVE_ICONV_libc_const CACHE)
 +  UNSET(HAVE_ICONV_libiconv_ CACHE)
 +  UNSET(HAVE_ICONV_libiconv_const CACHE)
 +  UNSET(ICONV_INCLUDE_DIR CACHE)
 +  UNSET(LIBICONV_PATH CACHE)
 +ENDIF(ENABLE_ICONV)
 +
 +IF(0) # CMake does not need XML support in libarchive
 +#
 +# Find Libxml2
 +#
 +FIND_PACKAGE(LibXml2)
 +IF(LIBXML2_FOUND)
 +  INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})
 +  LIST(APPEND ADDITIONAL_LIBS ${LIBXML2_LIBRARIES})
 +  SET(HAVE_LIBXML2 1)
 +  # libxml2's include files use iconv.h
 +  SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR})
 +  CHECK_INCLUDE_FILES("libxml/xmlreader.h" HAVE_LIBXML_XMLREADER_H)
 +  CHECK_INCLUDE_FILES("libxml/xmlwriter.h" HAVE_LIBXML_XMLWRITER_H)
 +  SET(CMAKE_REQUIRED_INCLUDES "")
 +ELSE(LIBXML2_FOUND)
 +  #
 +  # Find Expat
 +  #
 +  FIND_PACKAGE(EXPAT)
 +  IF(EXPAT_FOUND)
 +    INCLUDE_DIRECTORIES(${EXPAT_INCLUDE_DIR})
 +    LIST(APPEND ADDITIONAL_LIBS ${EXPAT_LIBRARIES})
 +    SET(HAVE_LIBEXPAT 1)
 +    LA_CHECK_INCLUDE_FILE("expat.h" HAVE_EXPAT_H)
 +  ENDIF(EXPAT_FOUND)
 +ENDIF(LIBXML2_FOUND)
 +ENDIF()
 +
 +#
 +# Check functions
 +#
 +IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
 +  #
 +  # During checking functions, we should use -fno-builtin to avoid the
 +  # failure of function detection which failure is an error "conflicting
 +  # types for built-in function" caused by using -Werror option.
 +  #
 +  SET(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
 +  SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-builtin")
 +ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
 +CHECK_SYMBOL_EXISTS(_CrtSetReportMode "crtdbg.h" HAVE__CrtSetReportMode)
 +CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS)
 +CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN)
 +CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT)
 +CHECK_FUNCTION_EXISTS_GLIBC(ctime_r HAVE_CTIME_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(fchdir HAVE_FCHDIR)
 +CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS)
 +CHECK_FUNCTION_EXISTS_GLIBC(fchmod HAVE_FCHMOD)
 +CHECK_FUNCTION_EXISTS_GLIBC(fchown HAVE_FCHOWN)
 +CHECK_FUNCTION_EXISTS_GLIBC(fcntl HAVE_FCNTL)
 +CHECK_FUNCTION_EXISTS_GLIBC(fdopendir HAVE_FDOPENDIR)
 +CHECK_FUNCTION_EXISTS_GLIBC(fork HAVE_FORK)
 +CHECK_FUNCTION_EXISTS_GLIBC(fstat HAVE_FSTAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(fstatat HAVE_FSTATAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(fstatfs HAVE_FSTATFS)
 +CHECK_FUNCTION_EXISTS_GLIBC(fstatvfs HAVE_FSTATVFS)
 +CHECK_FUNCTION_EXISTS_GLIBC(ftruncate HAVE_FTRUNCATE)
 +CHECK_FUNCTION_EXISTS_GLIBC(futimens HAVE_FUTIMENS)
 +CHECK_FUNCTION_EXISTS_GLIBC(futimes HAVE_FUTIMES)
 +CHECK_FUNCTION_EXISTS_GLIBC(futimesat HAVE_FUTIMESAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(geteuid HAVE_GETEUID)
 +CHECK_FUNCTION_EXISTS_GLIBC(getgrgid_r HAVE_GETGRGID_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(getgrnam_r HAVE_GETGRNAM_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(getpwnam_r HAVE_GETPWNAM_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(getpwuid_r HAVE_GETPWUID_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(getpid HAVE_GETPID)
 +CHECK_FUNCTION_EXISTS_GLIBC(getvfsbyname HAVE_GETVFSBYNAME)
 +CHECK_FUNCTION_EXISTS_GLIBC(gmtime_r HAVE_GMTIME_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(lchflags HAVE_LCHFLAGS)
 +CHECK_FUNCTION_EXISTS_GLIBC(lchmod HAVE_LCHMOD)
 +CHECK_FUNCTION_EXISTS_GLIBC(lchown HAVE_LCHOWN)
 +CHECK_FUNCTION_EXISTS_GLIBC(link HAVE_LINK)
 +CHECK_FUNCTION_EXISTS_GLIBC(localtime_r HAVE_LOCALTIME_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(lstat HAVE_LSTAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(lutimes HAVE_LUTIMES)
 +CHECK_FUNCTION_EXISTS_GLIBC(mbrtowc HAVE_MBRTOWC)
 +CHECK_FUNCTION_EXISTS_GLIBC(mbsnrtowcs HAVE_MBSNRTOWCS)
 +CHECK_FUNCTION_EXISTS_GLIBC(memmove HAVE_MEMMOVE)
 +CHECK_FUNCTION_EXISTS_GLIBC(mkdir HAVE_MKDIR)
 +CHECK_FUNCTION_EXISTS_GLIBC(mkfifo HAVE_MKFIFO)
 +CHECK_FUNCTION_EXISTS_GLIBC(mknod HAVE_MKNOD)
 +CHECK_FUNCTION_EXISTS_GLIBC(mkstemp HAVE_MKSTEMP)
 +CHECK_FUNCTION_EXISTS_GLIBC(nl_langinfo HAVE_NL_LANGINFO)
 +CHECK_FUNCTION_EXISTS_GLIBC(openat HAVE_OPENAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(pipe HAVE_PIPE)
 +CHECK_FUNCTION_EXISTS_GLIBC(poll HAVE_POLL)
 +CHECK_FUNCTION_EXISTS_GLIBC(readlink HAVE_READLINK)
 +CHECK_FUNCTION_EXISTS_GLIBC(select HAVE_SELECT)
 +CHECK_FUNCTION_EXISTS_GLIBC(setenv HAVE_SETENV)
 +CHECK_FUNCTION_EXISTS_GLIBC(setlocale HAVE_SETLOCALE)
 +CHECK_FUNCTION_EXISTS_GLIBC(sigaction HAVE_SIGACTION)
 +CHECK_FUNCTION_EXISTS_GLIBC(statfs HAVE_STATFS)
 +CHECK_FUNCTION_EXISTS_GLIBC(statvfs HAVE_STATVFS)
 +CHECK_FUNCTION_EXISTS_GLIBC(strchr HAVE_STRCHR)
 +CHECK_FUNCTION_EXISTS_GLIBC(strdup HAVE_STRDUP)
 +CHECK_FUNCTION_EXISTS_GLIBC(strerror HAVE_STRERROR)
 +CHECK_FUNCTION_EXISTS_GLIBC(strncpy_s HAVE_STRNCPY_S)
 +CHECK_FUNCTION_EXISTS_GLIBC(strrchr HAVE_STRRCHR)
 +CHECK_FUNCTION_EXISTS_GLIBC(symlink HAVE_SYMLINK)
 +CHECK_FUNCTION_EXISTS_GLIBC(timegm HAVE_TIMEGM)
 +CHECK_FUNCTION_EXISTS_GLIBC(tzset HAVE_TZSET)
 +CHECK_FUNCTION_EXISTS_GLIBC(unsetenv HAVE_UNSETENV)
 +CHECK_FUNCTION_EXISTS_GLIBC(utime HAVE_UTIME)
 +CHECK_FUNCTION_EXISTS_GLIBC(utimes HAVE_UTIMES)
 +CHECK_FUNCTION_EXISTS_GLIBC(utimensat HAVE_UTIMENSAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(vfork HAVE_VFORK)
 +CHECK_FUNCTION_EXISTS_GLIBC(wcrtomb HAVE_WCRTOMB)
 +CHECK_FUNCTION_EXISTS_GLIBC(wcscmp HAVE_WCSCMP)
 +CHECK_FUNCTION_EXISTS_GLIBC(wcscpy HAVE_WCSCPY)
 +CHECK_FUNCTION_EXISTS_GLIBC(wcslen HAVE_WCSLEN)
 +CHECK_FUNCTION_EXISTS_GLIBC(wcsnrtombs HAVE_WCSNRTOMBS)
 +CHECK_FUNCTION_EXISTS_GLIBC(wctomb HAVE_WCTOMB)
 +CHECK_FUNCTION_EXISTS_GLIBC(_ctime64_s HAVE__CTIME64_S)
 +CHECK_FUNCTION_EXISTS_GLIBC(_fseeki64 HAVE__FSEEKI64)
 +CHECK_FUNCTION_EXISTS_GLIBC(_get_timezone HAVE__GET_TIMEZONE)
 +CHECK_FUNCTION_EXISTS_GLIBC(_localtime64_s HAVE__LOCALTIME64_S)
 +CHECK_FUNCTION_EXISTS_GLIBC(_mkgmtime64 HAVE__MKGMTIME64)
 +
 +SET(CMAKE_REQUIRED_LIBRARIES "")
 +CHECK_FUNCTION_EXISTS(cygwin_conv_path HAVE_CYGWIN_CONV_PATH)
 +CHECK_FUNCTION_EXISTS(fseeko HAVE_FSEEKO)
 +CHECK_FUNCTION_EXISTS(strerror_r HAVE_STRERROR_R)
 +CHECK_FUNCTION_EXISTS(strftime HAVE_STRFTIME)
 +CHECK_FUNCTION_EXISTS(vprintf HAVE_VPRINTF)
 +CHECK_FUNCTION_EXISTS(wmemcmp HAVE_WMEMCMP)
 +CHECK_FUNCTION_EXISTS(wmemcpy HAVE_WMEMCPY)
 +
 +# Restore CMAKE_REQUIRED_FLAGS
 +IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
 +  SET(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS})
 +ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
 +
 +# Make sure we have the POSIX version of readdir_r, not the
 +# older 2-argument version.
 +CHECK_C_SOURCE_COMPILES(
 +  "#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}"
 +  HAVE_READDIR_R)
 +
 +
 +# Only detect readlinkat() if we also have AT_FDCWD in unistd.h.
 +# NOTE: linux requires fcntl.h for AT_FDCWD.
 +CHECK_C_SOURCE_COMPILES(
 +  "#include <fcntl.h>\n#include <unistd.h>\nint main() {char buf[10]; return readlinkat(AT_FDCWD, \"\", buf, 0);}"
 +  HAVE_READLINKAT)
 +
 +
 +# To verify major(), we need to both include the header
 +# of interest and verify that the result can be linked.
 +# CHECK_FUNCTION_EXISTS doesn't accept a header argument,
 +# CHECK_SYMBOL_EXISTS doesn't test linkage.
 +CHECK_C_SOURCE_COMPILES(
 +  "#include <sys/mkdev.h>\nint main() { return major(256); }"
 +  MAJOR_IN_MKDEV)
 +CHECK_C_SOURCE_COMPILES(
 +  "#include <sys/sysmacros.h>\nint main() { return major(256); }"
 +  MAJOR_IN_SYSMACROS)
 +
 +IF(HAVE_STRERROR_R)
 +  SET(HAVE_DECL_STRERROR_R 1)
 +ENDIF(HAVE_STRERROR_R)
 +
 +#
 +# Check defines
 +#
 +SET(headers "limits.h")
 +IF(HAVE_STDINT_H)
 +  LIST(APPEND headers "stdint.h")
 +ENDIF(HAVE_STDINT_H)
 +IF(HAVE_INTTYPES_H)
 +  LIST(APPEND headers "inttypes.h")
 +ENDIF(HAVE_INTTYPES_H)
 +CHECK_SYMBOL_EXISTS(EFTYPE           "errno.h"    HAVE_EFTYPE)
 +CHECK_SYMBOL_EXISTS(EILSEQ           "errno.h"    HAVE_EILSEQ)
 +CHECK_SYMBOL_EXISTS(D_MD_ORDER       "langinfo.h" HAVE_D_MD_ORDER)
 +CHECK_SYMBOL_EXISTS(INT64_MAX        "${headers}" HAVE_DECL_INT64_MAX)
 +CHECK_SYMBOL_EXISTS(INT64_MIN        "${headers}" HAVE_DECL_INT64_MIN)
 +CHECK_SYMBOL_EXISTS(UINT32_MAX       "${headers}" HAVE_DECL_UINT32_MAX)
 +CHECK_SYMBOL_EXISTS(UINT64_MAX       "${headers}" HAVE_DECL_UINT64_MAX)
 +CHECK_SYMBOL_EXISTS(SIZE_MAX         "${headers}" HAVE_DECL_SIZE_MAX)
 +CHECK_SYMBOL_EXISTS(SSIZE_MAX        "limits.h"   HAVE_DECL_SSIZE_MAX)
 +
 +#
 +# Check struct members
 +#
 +# Check for tm_gmtoff in struct tm
 +CHECK_STRUCT_MEMBER("struct tm" tm_gmtoff
 +    "time.h" HAVE_STRUCT_TM_TM_GMTOFF)
 +CHECK_STRUCT_MEMBER("struct tm" __tm_gmtoff
 +    "time.h" HAVE_STRUCT_TM___TM_GMTOFF)
 +
 +# Check for f_namemax in struct statfs
 +CHECK_STRUCT_MEMBER("struct statfs" f_namemax
 +    "sys/param.h;sys/mount.h" HAVE_STRUCT_STATFS_F_NAMEMAX)
 +
 +# Check for birthtime in struct stat
 +CHECK_STRUCT_MEMBER("struct stat" st_birthtime
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_BIRTHTIME)
 +
 +# Check for high-resolution timestamps in struct stat
 +CHECK_STRUCT_MEMBER("struct stat" st_birthtimespec.tv_nsec
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
 +CHECK_STRUCT_MEMBER("struct stat" st_mtimespec.tv_nsec
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
 +CHECK_STRUCT_MEMBER("struct stat" st_mtim.tv_nsec
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
 +CHECK_STRUCT_MEMBER("struct stat" st_mtime_n
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIME_N)
 +CHECK_STRUCT_MEMBER("struct stat" st_umtime
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_UMTIME)
 +CHECK_STRUCT_MEMBER("struct stat" st_mtime_usec
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIME_USEC)
 +# Check for block size support in struct stat
 +CHECK_STRUCT_MEMBER("struct stat" st_blksize
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_BLKSIZE)
 +# Check for st_flags in struct stat (BSD fflags)
 +CHECK_STRUCT_MEMBER("struct stat" st_flags
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_FLAGS)
 +
 +IF(HAVE_SYS_STATVFS_H)
 +  CHECK_STRUCT_MEMBER("struct statvfs" f_iosize
 +    "sys/types.h;sys/statvfs.h" HAVE_STRUCT_STATVFS_F_IOSIZE)
 +ENDIF()
 +
 +#
 +#
 +CHECK_STRUCT_MEMBER("struct tm" tm_sec
 +    "sys/types.h;sys/time.h;time.h" TIME_WITH_SYS_TIME)
 +
 +#
 +# Check for integer types
 +#
 +#
 +CHECK_TYPE_SIZE("short" SIZE_OF_SHORT)
 +CHECK_TYPE_SIZE("int" SIZE_OF_INT)
 +CHECK_TYPE_SIZE("long" SIZE_OF_LONG)
 +CHECK_TYPE_SIZE("long long"     SIZE_OF_LONG_LONG)
 +
 +CHECK_TYPE_SIZE("unsigned short" SIZE_OF_UNSIGNED_SHORT)
 +CHECK_TYPE_SIZE("unsigned" SIZE_OF_UNSIGNED)
 +CHECK_TYPE_SIZE("unsigned long" SIZE_OF_UNSIGNED_LONG)
 +CHECK_TYPE_SIZE("unsigned long long" SIZE_OF_UNSIGNED_LONG_LONG)
 +
 +CHECK_TYPE_SIZE("__int64" __INT64)
 +CHECK_TYPE_SIZE("unsigned __int64" UNSIGNED___INT64)
 +
 +CHECK_TYPE_SIZE(int16_t INT16_T) 
 +CHECK_TYPE_SIZE(int32_t INT32_T)
 +CHECK_TYPE_SIZE(int64_t INT64_T)
 +CHECK_TYPE_SIZE(intmax_t INTMAX_T)
 +CHECK_TYPE_SIZE(uint8_t UINT8_T) 
 +CHECK_TYPE_SIZE(uint16_t UINT16_T) 
 +CHECK_TYPE_SIZE(uint32_t UINT32_T) 
 +CHECK_TYPE_SIZE(uint64_t UINT64_T)
 +CHECK_TYPE_SIZE(uintmax_t UINTMAX_T)
 +
 +CHECK_TYPE_SIZE(dev_t       DEV_T)
 +IF(NOT HAVE_DEV_T)
 +  IF(MSVC)
 +    SET(dev_t "unsigned int")
 +  ENDIF(MSVC)
 +ENDIF(NOT HAVE_DEV_T)
 +#
 +CHECK_TYPE_SIZE(gid_t       GID_T)
 +IF(NOT HAVE_GID_T)
 +  IF(WIN32)
 +    SET(gid_t "short")
 +  ELSE(WIN32)
 +    SET(gid_t "unsigned int")
 +  ENDIF(WIN32)
 +ENDIF(NOT HAVE_GID_T)
 +#
 +CHECK_TYPE_SIZE(id_t        ID_T)
 +IF(NOT HAVE_ID_T)
 +  IF(WIN32)
 +    SET(id_t "short")
 +  ELSE(WIN32)
 +    SET(id_t "unsigned int")
 +  ENDIF(WIN32)
 +ENDIF(NOT HAVE_ID_T)
 +#
 +CHECK_TYPE_SIZE(mode_t      MODE_T)
 +IF(NOT HAVE_MODE_T)
 +  IF(WIN32)
 +    SET(mode_t "unsigned short")
 +  ELSE(WIN32)
 +    SET(mode_t "int")
 +  ENDIF(WIN32)
 +ENDIF(NOT HAVE_MODE_T)
 +#
 +CHECK_TYPE_SIZE(off_t       OFF_T)
 +IF(NOT HAVE_OFF_T)
 +  SET(off_t "__int64")
 +ENDIF(NOT HAVE_OFF_T)
 +#
 +CHECK_TYPE_SIZE(size_t      SIZE_T)
 +IF(NOT HAVE_SIZE_T)
 +  IF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(size_t "uint64_t")
 +  ELSE("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(size_t   "uint32_t")
 +  ENDIF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +ENDIF(NOT HAVE_SIZE_T)
 +#
 +CHECK_TYPE_SIZE(ssize_t     SSIZE_T)
 +IF(NOT HAVE_SSIZE_T)
 +  IF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(ssize_t "int64_t")
 +  ELSE("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(ssize_t "long")
 +  ENDIF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +ENDIF(NOT HAVE_SSIZE_T)
 +#
 +CHECK_TYPE_SIZE(uid_t       UID_T)
 +IF(NOT HAVE_UID_T)
 +  IF(WIN32)
 +    SET(uid_t "short")
 +  ELSE(WIN32)
 +    SET(uid_t "unsigned int")
 +  ENDIF(WIN32)
 +ENDIF(NOT HAVE_UID_T)
 +#
 +CHECK_TYPE_SIZE(pid_t       PID_T)
 +IF(NOT HAVE_PID_T)
 +  IF(WIN32)
 +    SET(pid_t "int")
 +  ELSE(WIN32)
 +    MESSAGE(FATAL_ERROR "pid_t doesn't exist on this platform?")
 +  ENDIF(WIN32)
 +ENDIF(NOT HAVE_PID_T)
 +#
 +CHECK_TYPE_SIZE(intptr_t   INTPTR_T)
 +IF(NOT HAVE_INTPTR_T)
 +  IF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(intptr_t "int64_t")
 +  ELSE()
 +    SET(intptr_t "int32_t")
 +  ENDIF()
 +ENDIF(NOT HAVE_INTPTR_T)
 +#
 +CHECK_TYPE_SIZE(uintptr_t   UINTPTR_T)
 +IF(NOT HAVE_UINTPTR_T)
 +  IF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(uintptr_t "uint64_t")
 +  ELSE()
 +    SET(uintptr_t "uint32_t")
 +  ENDIF()
 +ENDIF(NOT HAVE_UINTPTR_T)
 +#
 +CHECK_TYPE_SIZE(wchar_t     SIZEOF_WCHAR_T)
 +IF(HAVE_SIZEOF_WCHAR_T)
 +  SET(HAVE_WCHAR_T 1)
 +ENDIF(HAVE_SIZEOF_WCHAR_T)
 +#
 +# Check if _FILE_OFFSET_BITS macro needed for large files
 +#
 +CHECK_FILE_OFFSET_BITS()
 +
 +#
 +# Check for Extended Attribute libraries, headers, and functions
 +#
 +IF(ENABLE_XATTR)
 +  LA_CHECK_INCLUDE_FILE(attr/xattr.h     HAVE_ATTR_XATTR_H)
 +  LA_CHECK_INCLUDE_FILE(sys/xattr.h      HAVE_SYS_XATTR_H)
 +  LA_CHECK_INCLUDE_FILE(sys/extattr.h      HAVE_SYS_EXTATTR_H)
 +  CHECK_LIBRARY_EXISTS(attr "setxattr" "" HAVE_LIBATTR)
 +  IF(HAVE_LIBATTR)
 +    SET(CMAKE_REQUIRED_LIBRARIES "attr")
 +  ENDIF(HAVE_LIBATTR)
 +  CHECK_SYMBOL_EXISTS(EXTATTR_NAMESPACE_USER "sys/types.h;sys/extattr.h" HAVE_DECL_EXTATTR_NAMESPACE_USER)
 +  CHECK_FUNCTION_EXISTS_GLIBC(extattr_get_file HAVE_EXTATTR_GET_FILE)
 +  CHECK_FUNCTION_EXISTS_GLIBC(extattr_list_file HAVE_EXTATTR_LIST_FILE)
 +  CHECK_FUNCTION_EXISTS_GLIBC(extattr_set_fd HAVE_EXTATTR_SET_FD)
 +  CHECK_FUNCTION_EXISTS_GLIBC(extattr_set_file HAVE_EXTATTR_SET_FILE)
 +  CHECK_FUNCTION_EXISTS_GLIBC(fgetxattr HAVE_FGETXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(flistxattr HAVE_FLISTXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(fsetxattr HAVE_FSETXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(getxattr HAVE_GETXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(lgetxattr HAVE_LGETXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(listxattr HAVE_LISTXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(llistxattr HAVE_LLISTXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(lsetxattr HAVE_LSETXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(fgetea HAVE_FGETEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(flistea HAVE_FLISTEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(fsetea HAVE_FSETEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(getea HAVE_GETEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(lgetea HAVE_LGETEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(listea HAVE_LISTEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(llistea HAVE_LLISTEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(lsetea HAVE_LSETEA)
 +ELSE(ENABLE_XATTR)
 +  SET(HAVE_ATTR_LIB FALSE)
 +  SET(HAVE_ATTR_XATTR_H FALSE)
 +  SET(HAVE_DECL_EXTATTR_NAMESPACE_USER FALSE)
 +  SET(HAVE_EXTATTR_GET_FILE FALSE)
 +  SET(HAVE_EXTATTR_LIST_FILE FALSE)
 +  SET(HAVE_EXTATTR_SET_FD FALSE)
 +  SET(HAVE_EXTATTR_SET_FILE FALSE)
 +  SET(HAVE_FGETEA FALSE)
 +  SET(HAVE_FGETXATTR FALSE)
 +  SET(HAVE_FLISTEA FALSE)
 +  SET(HAVE_FLISTXATTR FALSE)
 +  SET(HAVE_FSETEA FALSE)
 +  SET(HAVE_FSETXATTR FALSE)
 +  SET(HAVE_GETEA FALSE)
 +  SET(HAVE_GETXATTR FALSE)
 +  SET(HAVE_LGETEA FALSE)
 +  SET(HAVE_LGETXATTR FALSE)
 +  SET(HAVE_LISTEA FALSE)
 +  SET(HAVE_LISTXATTR FALSE)
 +  SET(HAVE_LLISTEA FALSE)
 +  SET(HAVE_LLISTXATTR FALSE)
 +  SET(HAVE_LSETEA FALSE)
 +  SET(HAVE_LSETXATTR FALSE)
 +  SET(HAVE_SYS_EXTATTR_H FALSE)
 +  SET(HAVE_SYS_XATTR_H FALSE)
 +ENDIF(ENABLE_XATTR)
 +
 +#
 +# Check for ACL libraries, headers, and functions
 +#
 +# The ACL support in libarchive is written against the POSIX1e draft,
 +# which was never officially approved and varies quite a bit across
 +# platforms.  Worse, some systems have completely non-POSIX acl functions,
 +# which makes the following checks rather more complex than I would like.
 +#
 +IF(ENABLE_ACL)
 +  CHECK_LIBRARY_EXISTS(acl "acl_get_file" "" HAVE_LIBACL)
 +  IF(HAVE_LIBACL)
 +    SET(CMAKE_REQUIRED_LIBRARIES "acl")
 +    FIND_LIBRARY(ACL_LIBRARY NAMES acl)
 +    LIST(APPEND ADDITIONAL_LIBS ${ACL_LIBRARY})
 +  ENDIF(HAVE_LIBACL)
 +  #
 +  CHECK_FUNCTION_EXISTS_GLIBC(acl_create_entry HAVE_ACL_CREATE_ENTRY)
 +  CHECK_FUNCTION_EXISTS_GLIBC(acl_init HAVE_ACL_INIT)
 +  CHECK_FUNCTION_EXISTS_GLIBC(acl_set_fd HAVE_ACL_SET_FD)
 +  CHECK_FUNCTION_EXISTS_GLIBC(acl_set_fd_np HAVE_ACL_SET_FD_NP)
 +  CHECK_FUNCTION_EXISTS_GLIBC(acl_set_file HAVE_ACL_SET_FILE)
 +  CHECK_TYPE_EXISTS(acl_permset_t "${INCLUDES}"    HAVE_ACL_PERMSET_T)
 +
 +  # The "acl_get_perm()" function was omitted from the POSIX draft.
 +  # (It's a pretty obvious oversight; otherwise, there's no way to
 +  # test for specific permissions in a permset.)  Linux uses the obvious
 +  # name, FreeBSD adds _np to mark it as "non-Posix extension."
 +  # Test for both as a double-check that we really have POSIX-style ACL support.
 +  CHECK_FUNCTION_EXISTS(acl_get_perm HAVE_ACL_GET_PERM)
 +  CHECK_FUNCTION_EXISTS(acl_get_perm_np HAVE_ACL_GET_PERM_NP)
 +  CHECK_FUNCTION_EXISTS(acl_get_link HAVE_ACL_GET_LINK)
 +  CHECK_FUNCTION_EXISTS(acl_get_link_np HAVE_ACL_GET_LINK_NP)
 +
 +  # MacOS has an acl.h that isn't POSIX.  It can be detected by
 +  # checking for ACL_USER
 +  CHECK_SYMBOL_EXISTS(ACL_USER "${INCLUDES}" HAVE_ACL_USER)
 +ELSE(ENABLE_ACL)
 +  # If someone runs cmake, then disables ACL support, we need
 +  # to forcibly override the cached values for these.
 +  SET(HAVE_ACL_CREATE_ENTRY FALSE)
 +  SET(HAVE_ACL_GET_LINK FALSE)
 +  SET(HAVE_ACL_GET_LINK_NP FALSE)
 +  SET(HAVE_ACL_GET_PERM FALSE)
 +  SET(HAVE_ACL_GET_PERM_NP FALSE)
 +  SET(HAVE_ACL_INIT FALSE)
 +  SET(HAVE_ACL_LIB FALSE)
 +  SET(HAVE_ACL_PERMSET_T FALSE)
 +  SET(HAVE_ACL_SET_FD FALSE)
 +  SET(HAVE_ACL_SET_FD_NP FALSE)
 +  SET(HAVE_ACL_SET_FILE FALSE)
 +  SET(HAVE_ACL_USER FALSE)
 +ENDIF(ENABLE_ACL)
 +
 +#
 +# Check MD5/RMD160/SHA support
 +# NOTE: Crypto checks must be run last before generating config.h
 +#
 +CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" LIBC)
 +CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC2)
 +CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC3)
 +CHECK_CRYPTO("MD5;SHA1;SHA256;SHA384;SHA512" LIBSYSTEM)
 +CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" NETTLE)
 +CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" OPENSSL)
 +
 +# Libmd has to be probed after OpenSSL.
 +CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA512" LIBMD)
 +
 +CHECK_CRYPTO_WIN("MD5;SHA1;SHA256;SHA384;SHA512")
 +
 +# Generate "config.h" from "build/cmake/config.h.in"
 +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in
 +	${CMAKE_CURRENT_BINARY_DIR}/config.h)
 +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
 +ADD_DEFINITIONS(-DHAVE_CONFIG_H)
 +
 +#
 +# Register installation of PDF documents.
 +#
 +IF(WIN32 AND NOT CYGWIN)
 +  #
 +  # On Windows platform, It's better that we install PDF documents
 +  # on one's computer.
 +  # These PDF documents are available in the release package.
 +  #
 +  IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/doc/pdf)
 +    INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc/pdf
 +            DESTINATION share/man
 +            FILES_MATCHING PATTERN "*.pdf"
 +    )
 +  ENDIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/doc/pdf)
 +ENDIF(WIN32 AND NOT CYGWIN)
 +#
 +#
 +#
 +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/libarchive)
 +#
 +IF(MSVC)
 +  ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
 +ENDIF(MSVC)
 +
 +# We need CoreServices on Mac OS.
 +IF(APPLE)
 +  LIST(APPEND ADDITIONAL_LIBS "-framework CoreServices")
 +ENDIF(APPLE)
 +
 +add_subdirectory(libarchive)
 +
 +install(FILES COPYING DESTINATION ${CMake_DOC_DEST}/cmlibarchive)
diff --cc Utilities/cmlibarchive/libarchive/archive.h
index a815e49,0000000..9b6b1b0
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive.h
+++ b/Utilities/cmlibarchive/libarchive/archive.h
@@@ -1,839 -1,0 +1,826 @@@
 +/*-
 + * 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: src/lib/libarchive/archive.h.in,v 1.50 2008/05/26 17:00:22 kientzle Exp $
 + */
 +
 +#ifndef ARCHIVE_H_INCLUDED
 +#define	ARCHIVE_H_INCLUDED
 +
 +#include <sys/stat.h>
 +#include <stddef.h>  /* for wchar_t */
 +#include <stdio.h> /* For FILE * */
 +
 +/*
 + * Note: archive.h is for use outside of libarchive; the configuration
 + * headers (config.h, archive_platform.h, etc.) are purely internal.
 + * Do NOT use HAVE_XXX configuration macros to control the behavior of
 + * this header!  If you must conditionalize, use predefined compiler and/or
 + * platform macros.
 + */
 +#if defined(__BORLANDC__) && __BORLANDC__ >= 0x560
 +# include <stdint.h>
 +#elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__) && !defined(_SCO_DS) && !defined(__osf__)
 +# include <inttypes.h>
 +#endif
 +
 +/* Borland symbols are case-insensitive.  This workaround only works
 +   within CMake because we do not mix compilers.  */
 +#if defined(__BORLANDC__)
 +# define archive_read_open_FILE archive_read_open_FILE_
 +# define archive_write_open_FILE archive_write_open_FILE_
 +#endif
 +
 +/* Get appropriate definitions of standard POSIX-style types. */
 +/* These should match the types used in 'struct stat' */
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +# define	__LA_INT64_T	__int64
 +# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
 +#  define	__LA_SSIZE_T	ssize_t
 +# elif defined(_WIN64)
 +#  define	__LA_SSIZE_T	__int64
 +# else
 +#  define	__LA_SSIZE_T	long
 +# endif
 +# if defined(__BORLANDC__)
 +#  define	__LA_UID_T	uid_t
 +#  define	__LA_GID_T	gid_t
 +# else
 +#  define	__LA_UID_T	short
 +#  define	__LA_GID_T	short
 +# endif
 +#else
 +# include <unistd.h>  /* ssize_t, uid_t, and gid_t */
 +# if defined(_SCO_DS) || defined(__osf__)
 +#  define	__LA_INT64_T	long long
 +# else
 +#  define	__LA_INT64_T	int64_t
 +# endif
 +# define	__LA_SSIZE_T	ssize_t
 +# define	__LA_UID_T	uid_t
 +# define	__LA_GID_T	gid_t
 +#endif
 +
 +/*
 + * On Windows, define LIBARCHIVE_STATIC if you're building or using a
 + * .lib.  The default here assumes you're building a DLL.  Only
 + * libarchive source should ever define __LIBARCHIVE_BUILD.
 + */
 +#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC)
 +# ifdef __LIBARCHIVE_BUILD
 +#  ifdef __GNUC__
 +#   define __LA_DECL	__attribute__((dllexport)) extern
 +#  else
 +#   define __LA_DECL	__declspec(dllexport)
 +#  endif
 +# else
 +#  ifdef __GNUC__
 +#   define __LA_DECL
 +#  else
 +#   define __LA_DECL	__declspec(dllimport)
 +#  endif
 +# endif
 +#else
 +/* Static libraries or non-Windows needs no special declaration. */
 +# define __LA_DECL
 +#endif
 +
 +#if defined(__GNUC__) && __GNUC__ >= 3 && !defined(__MINGW32__)
 +#define	__LA_PRINTF(fmtarg, firstvararg) \
 +	__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
 +#else
 +#define	__LA_PRINTF(fmtarg, firstvararg)	/* nothing */
 +#endif
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/*
 + * The version number is provided as both a macro and a function.
 + * The macro identifies the installed header; the function identifies
 + * the library version (which may not be the same if you're using a
 + * dynamically-linked version of the library).  Of course, if the
 + * header and library are very different, you should expect some
 + * strangeness.  Don't do that.
 + */
 +
 +/*
 + * The version number is expressed as a single integer that makes it
 + * easy to compare versions at build time: for version a.b.c, the
 + * version number is printf("%d%03d%03d",a,b,c).  For example, if you
 + * know your application requires version 2.12.108 or later, you can
-  * assert that ARCHIVE_VERSION >= 2012108.
-  *
-  * This single-number format was introduced with libarchive 1.9.0 in
-  * the libarchive 1.x family and libarchive 2.2.4 in the libarchive
-  * 2.x family.  The following may be useful if you really want to do
-  * feature detection for earlier libarchive versions (which defined
-  * ARCHIVE_API_VERSION and ARCHIVE_API_FEATURE instead):
-  *
-  * #ifndef ARCHIVE_VERSION_NUMBER
-  * #define ARCHIVE_VERSION_NUMBER	\
-  *             (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
-  * #endif
++ * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
 + */
 +/* Note: Compiler will complain if this does not match archive_entry.h! */
- #define	ARCHIVE_VERSION_NUMBER 3000001
++#define	ARCHIVE_VERSION_NUMBER 3000002
 +__LA_DECL int		archive_version_number(void);
 +
 +/*
 + * Textual name/version of the library, useful for version displays.
 + */
- #define	ARCHIVE_VERSION_STRING "libarchive 3.0.1b"
++#define	ARCHIVE_VERSION_STRING "libarchive 3.0.2"
 +__LA_DECL const char *	archive_version_string(void);
 +
 +/* Declare our basic types. */
 +struct archive;
 +struct archive_entry;
 +
 +/*
 + * Error codes: Use archive_errno() and archive_error_string()
 + * to retrieve details.  Unless specified otherwise, all functions
 + * that return 'int' use these codes.
 + */
 +#define	ARCHIVE_EOF	  1	/* Found end of archive. */
 +#define	ARCHIVE_OK	  0	/* Operation was successful. */
 +#define	ARCHIVE_RETRY	(-10)	/* Retry might succeed. */
 +#define	ARCHIVE_WARN	(-20)	/* Partial success. */
 +/* For example, if write_header "fails", then you can't push data. */
 +#define	ARCHIVE_FAILED	(-25)	/* Current operation cannot complete. */
 +/* But if write_header is "fatal," then this archive is dead and useless. */
 +#define	ARCHIVE_FATAL	(-30)	/* No more operations are possible. */
 +
 +/*
 + * As far as possible, archive_errno returns standard platform errno codes.
 + * Of course, the details vary by platform, so the actual definitions
 + * here are stored in "archive_platform.h".  The symbols are listed here
 + * for reference; as a rule, clients should not need to know the exact
 + * platform-dependent error code.
 + */
 +/* Unrecognized or invalid file format. */
 +/* #define	ARCHIVE_ERRNO_FILE_FORMAT */
 +/* Illegal usage of the library. */
 +/* #define	ARCHIVE_ERRNO_PROGRAMMER_ERROR */
 +/* Unknown or unclassified error. */
 +/* #define	ARCHIVE_ERRNO_MISC */
 +
 +/*
 + * Callbacks are invoked to automatically read/skip/write/open/close the
 + * archive. You can provide your own for complex tasks (like breaking
 + * archives across multiple tapes) or use standard ones built into the
 + * library.
 + */
 +
 +/* Returns pointer and size of next block of data from archive. */
 +typedef __LA_SSIZE_T	archive_read_callback(struct archive *,
 +			    void *_client_data, const void **_buffer);
 +
 +/* Skips at most request bytes from archive and returns the skipped amount.
 + * This may skip fewer bytes than requested; it may even skip zero bytes.
 + * If you do skip fewer bytes than requested, libarchive will invoke your
 + * read callback and discard data as necessary to make up the full skip.
 + */
 +typedef __LA_INT64_T	archive_skip_callback(struct archive *,
 +			    void *_client_data, __LA_INT64_T request);
 +
 +/* Seeks to specified location in the file and returns the position.
 + * Whence values are SEEK_SET, SEEK_CUR, SEEK_END from stdio.h.
 + * Return ARCHIVE_FATAL if the seek fails for any reason.
 + */
 +typedef __LA_INT64_T	archive_seek_callback(struct archive *,
 +    void *_client_data, __LA_INT64_T offset, int whence);
 +
 +/* Returns size actually written, zero on EOF, -1 on error. */
 +typedef __LA_SSIZE_T	archive_write_callback(struct archive *,
 +			    void *_client_data,
 +			    const void *_buffer, size_t _length);
 +
 +typedef int	archive_open_callback(struct archive *, void *_client_data);
 +
 +typedef int	archive_close_callback(struct archive *, void *_client_data);
 +
 +/*
 + * Codes to identify various stream filters.
 + */
 +#define	ARCHIVE_FILTER_NONE	0
 +#define	ARCHIVE_FILTER_GZIP	1
 +#define	ARCHIVE_FILTER_BZIP2	2
 +#define	ARCHIVE_FILTER_COMPRESS	3
 +#define	ARCHIVE_FILTER_PROGRAM	4
 +#define	ARCHIVE_FILTER_LZMA	5
 +#define	ARCHIVE_FILTER_XZ	6
 +#define	ARCHIVE_FILTER_UU	7
 +#define	ARCHIVE_FILTER_RPM	8
 +#define	ARCHIVE_FILTER_LZIP	9
 +
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +#define	ARCHIVE_COMPRESSION_NONE	ARCHIVE_FILTER_NONE
 +#define	ARCHIVE_COMPRESSION_GZIP	ARCHIVE_FILTER_GZIP
 +#define	ARCHIVE_COMPRESSION_BZIP2	ARCHIVE_FILTER_BZIP2
 +#define	ARCHIVE_COMPRESSION_COMPRESS	ARCHIVE_FILTER_COMPRESS
 +#define	ARCHIVE_COMPRESSION_PROGRAM	ARCHIVE_FILTER_PROGRAM
 +#define	ARCHIVE_COMPRESSION_LZMA	ARCHIVE_FILTER_LZMA
 +#define	ARCHIVE_COMPRESSION_XZ		ARCHIVE_FILTER_XZ
 +#define	ARCHIVE_COMPRESSION_UU		ARCHIVE_FILTER_UU
 +#define	ARCHIVE_COMPRESSION_RPM		ARCHIVE_FILTER_RPM
 +#define	ARCHIVE_COMPRESSION_LZIP	ARCHIVE_FILTER_LZIP
 +#endif
 +
 +/*
 + * Codes returned by archive_format.
 + *
 + * Top 16 bits identifies the format family (e.g., "tar"); lower
 + * 16 bits indicate the variant.  This is updated by read_next_header.
 + * Note that the lower 16 bits will often vary from entry to entry.
 + * In some cases, this variation occurs as libarchive learns more about
 + * the archive (for example, later entries might utilize extensions that
 + * weren't necessary earlier in the archive; in this case, libarchive
 + * will change the format code to indicate the extended format that
 + * was used).  In other cases, it's because different tools have
 + * modified the archive and so different parts of the archive
 + * actually have slightly different formats.  (Both tar and cpio store
 + * format codes in each entry, so it is quite possible for each
 + * entry to be in a different format.)
 + */
 +#define	ARCHIVE_FORMAT_BASE_MASK		0xff0000
 +#define	ARCHIVE_FORMAT_CPIO			0x10000
 +#define	ARCHIVE_FORMAT_CPIO_POSIX		(ARCHIVE_FORMAT_CPIO | 1)
 +#define	ARCHIVE_FORMAT_CPIO_BIN_LE		(ARCHIVE_FORMAT_CPIO | 2)
 +#define	ARCHIVE_FORMAT_CPIO_BIN_BE		(ARCHIVE_FORMAT_CPIO | 3)
 +#define	ARCHIVE_FORMAT_CPIO_SVR4_NOCRC		(ARCHIVE_FORMAT_CPIO | 4)
 +#define	ARCHIVE_FORMAT_CPIO_SVR4_CRC		(ARCHIVE_FORMAT_CPIO | 5)
 +#define	ARCHIVE_FORMAT_CPIO_AFIO_LARGE		(ARCHIVE_FORMAT_CPIO | 6)
 +#define	ARCHIVE_FORMAT_SHAR			0x20000
 +#define	ARCHIVE_FORMAT_SHAR_BASE		(ARCHIVE_FORMAT_SHAR | 1)
 +#define	ARCHIVE_FORMAT_SHAR_DUMP		(ARCHIVE_FORMAT_SHAR | 2)
 +#define	ARCHIVE_FORMAT_TAR			0x30000
 +#define	ARCHIVE_FORMAT_TAR_USTAR		(ARCHIVE_FORMAT_TAR | 1)
 +#define	ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE	(ARCHIVE_FORMAT_TAR | 2)
 +#define	ARCHIVE_FORMAT_TAR_PAX_RESTRICTED	(ARCHIVE_FORMAT_TAR | 3)
 +#define	ARCHIVE_FORMAT_TAR_GNUTAR		(ARCHIVE_FORMAT_TAR | 4)
 +#define	ARCHIVE_FORMAT_ISO9660			0x40000
 +#define	ARCHIVE_FORMAT_ISO9660_ROCKRIDGE	(ARCHIVE_FORMAT_ISO9660 | 1)
 +#define	ARCHIVE_FORMAT_ZIP			0x50000
 +#define	ARCHIVE_FORMAT_EMPTY			0x60000
 +#define	ARCHIVE_FORMAT_AR			0x70000
 +#define	ARCHIVE_FORMAT_AR_GNU			(ARCHIVE_FORMAT_AR | 1)
 +#define	ARCHIVE_FORMAT_AR_BSD			(ARCHIVE_FORMAT_AR | 2)
 +#define	ARCHIVE_FORMAT_MTREE			0x80000
 +#define	ARCHIVE_FORMAT_RAW			0x90000
 +#define	ARCHIVE_FORMAT_XAR			0xA0000
 +#define	ARCHIVE_FORMAT_LHA			0xB0000
 +#define	ARCHIVE_FORMAT_CAB			0xC0000
 +#define	ARCHIVE_FORMAT_RAR			0xD0000
 +#define	ARCHIVE_FORMAT_7ZIP			0xE0000
 +
 +/*-
 + * Basic outline for reading an archive:
 + *   1) Ask archive_read_new for an archive reader object.
 + *   2) Update any global properties as appropriate.
 + *      In particular, you'll certainly want to call appropriate
 + *      archive_read_support_XXX functions.
 + *   3) Call archive_read_open_XXX to open the archive
 + *   4) Repeatedly call archive_read_next_header to get information about
 + *      successive archive entries.  Call archive_read_data to extract
 + *      data for entries of interest.
 + *   5) Call archive_read_finish to end processing.
 + */
 +__LA_DECL struct archive	*archive_read_new(void);
 +
 +/*
 + * The archive_read_support_XXX calls enable auto-detect for this
 + * archive handle.  They also link in the necessary support code.
 + * For example, if you don't want bzlib linked in, don't invoke
 + * support_compression_bzip2().  The "all" functions provide the
 + * obvious shorthand.
 + */
 +
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +__LA_DECL int archive_read_support_compression_all(struct archive *);
 +__LA_DECL int archive_read_support_compression_bzip2(struct archive *);
 +__LA_DECL int archive_read_support_compression_compress(struct archive *);
 +__LA_DECL int archive_read_support_compression_gzip(struct archive *);
 +__LA_DECL int archive_read_support_compression_lzip(struct archive *);
 +__LA_DECL int archive_read_support_compression_lzma(struct archive *);
 +__LA_DECL int archive_read_support_compression_none(struct archive *);
 +__LA_DECL int archive_read_support_compression_program(struct archive *,
 +		     const char *command);
 +__LA_DECL int archive_read_support_compression_program_signature
 +		(struct archive *, const char *,
 +				    const void * /* match */, size_t);
 +
 +__LA_DECL int archive_read_support_compression_rpm(struct archive *);
 +__LA_DECL int archive_read_support_compression_uu(struct archive *);
 +__LA_DECL int archive_read_support_compression_xz(struct archive *);
 +#endif
 +
 +__LA_DECL int archive_read_support_filter_all(struct archive *);
 +__LA_DECL int archive_read_support_filter_bzip2(struct archive *);
 +__LA_DECL int archive_read_support_filter_compress(struct archive *);
 +__LA_DECL int archive_read_support_filter_gzip(struct archive *);
 +__LA_DECL int archive_read_support_filter_lzip(struct archive *);
 +__LA_DECL int archive_read_support_filter_lzma(struct archive *);
 +__LA_DECL int archive_read_support_filter_none(struct archive *);
 +__LA_DECL int archive_read_support_filter_program(struct archive *,
 +		     const char *command);
 +__LA_DECL int archive_read_support_filter_program_signature
 +		(struct archive *, const char *,
 +				    const void * /* match */, size_t);
 +
 +__LA_DECL int archive_read_support_filter_rpm(struct archive *);
 +__LA_DECL int archive_read_support_filter_uu(struct archive *);
 +__LA_DECL int archive_read_support_filter_xz(struct archive *);
 +
 +__LA_DECL int archive_read_support_format_7zip(struct archive *);
 +__LA_DECL int archive_read_support_format_all(struct archive *);
 +__LA_DECL int archive_read_support_format_ar(struct archive *);
 +__LA_DECL int archive_read_support_format_by_code(struct archive *, int);
 +__LA_DECL int archive_read_support_format_cab(struct archive *);
 +__LA_DECL int archive_read_support_format_cpio(struct archive *);
 +__LA_DECL int archive_read_support_format_empty(struct archive *);
 +__LA_DECL int archive_read_support_format_gnutar(struct archive *);
 +__LA_DECL int archive_read_support_format_iso9660(struct archive *);
 +__LA_DECL int archive_read_support_format_lha(struct archive *);
 +__LA_DECL int archive_read_support_format_mtree(struct archive *);
 +__LA_DECL int archive_read_support_format_rar(struct archive *);
 +__LA_DECL int archive_read_support_format_raw(struct archive *);
 +__LA_DECL int archive_read_support_format_tar(struct archive *);
 +__LA_DECL int archive_read_support_format_xar(struct archive *);
 +__LA_DECL int archive_read_support_format_zip(struct archive *);
 +
 +/* Set various callbacks. */
 +__LA_DECL int archive_read_set_open_callback(struct archive *,
 +    archive_open_callback *);
 +__LA_DECL int archive_read_set_read_callback(struct archive *,
 +    archive_read_callback *);
 +__LA_DECL int archive_read_set_seek_callback(struct archive *,
 +    archive_seek_callback *);
 +__LA_DECL int archive_read_set_skip_callback(struct archive *,
 +    archive_skip_callback *);
 +__LA_DECL int archive_read_set_close_callback(struct archive *,
 +    archive_close_callback *);
 +/* The callback data is provided to all of the callbacks above. */
 +__LA_DECL int archive_read_set_callback_data(struct archive *, void *);
 +/* Opening freezes the callbacks. */
 +__LA_DECL int archive_read_open1(struct archive *);
 +
 +/* Convenience wrappers around the above. */
 +__LA_DECL int archive_read_open(struct archive *, void *_client_data,
 +		     archive_open_callback *, archive_read_callback *,
 +		     archive_close_callback *);
 +__LA_DECL int archive_read_open2(struct archive *, void *_client_data,
 +		     archive_open_callback *, archive_read_callback *,
 +		     archive_skip_callback *, archive_close_callback *);
 +
 +/*
 + * A variety of shortcuts that invoke archive_read_open() with
 + * canned callbacks suitable for common situations.  The ones that
 + * accept a block size handle tape blocking correctly.
 + */
 +/* Use this if you know the filename.  Note: NULL indicates stdin. */
 +__LA_DECL int archive_read_open_filename(struct archive *,
 +		     const char *_filename, size_t _block_size);
 +__LA_DECL int archive_read_open_filename_w(struct archive *,
 +		     const wchar_t *_filename, size_t _block_size);
 +/* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
 +__LA_DECL int archive_read_open_file(struct archive *,
 +		     const char *_filename, size_t _block_size);
 +/* Read an archive that's stored in memory. */
 +__LA_DECL int archive_read_open_memory(struct archive *,
 +		     void * buff, size_t size);
 +/* A more involved version that is only used for internal testing. */
 +__LA_DECL int archive_read_open_memory2(struct archive *a, void *buff,
 +		     size_t size, size_t read_size);
 +/* Read an archive that's already open, using the file descriptor. */
 +__LA_DECL int archive_read_open_fd(struct archive *, int _fd,
 +		     size_t _block_size);
 +/* Read an archive that's already open, using a FILE *. */
 +/* Note: DO NOT use this with tape drives. */
 +__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file);
 +
 +/* Parses and returns next entry header. */
 +__LA_DECL int archive_read_next_header(struct archive *,
 +		     struct archive_entry **);
 +
 +/* Parses and returns next entry header using the archive_entry passed in */
 +__LA_DECL int archive_read_next_header2(struct archive *,
 +		     struct archive_entry *);
 +
 +/*
 + * Retrieve the byte offset in UNCOMPRESSED data where last-read
 + * header started.
 + */
 +__LA_DECL __LA_INT64_T		 archive_read_header_position(struct archive *);
 +
 +/* Read data from the body of an entry.  Similar to read(2). */
 +__LA_DECL __LA_SSIZE_T		 archive_read_data(struct archive *,
 +				    void *, size_t);
 +
 +/*
 + * A zero-copy version of archive_read_data that also exposes the file offset
 + * of each returned block.  Note that the client has no way to specify
 + * the desired size of the block.  The API does guarantee that offsets will
 + * be strictly increasing and that returned blocks will not overlap.
 + */
 +__LA_DECL int archive_read_data_block(struct archive *a,
 +		    const void **buff, size_t *size, __LA_INT64_T *offset);
 +
 +/*-
 + * Some convenience functions that are built on archive_read_data:
 + *  'skip': skips entire entry
 + *  'into_buffer': writes data into memory buffer that you provide
 + *  'into_fd': writes data to specified filedes
 + */
 +__LA_DECL int archive_read_data_skip(struct archive *);
- __LA_DECL int archive_read_data_into_buffer(struct archive *,
- 			    void *buffer, __LA_SSIZE_T len);
 +__LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
 +
 +/*
 + * Set read options.
 + */
 +/* Apply option to the format only. */
 +__LA_DECL int archive_read_set_format_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option to the filter only. */
 +__LA_DECL int archive_read_set_filter_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option to both the format and the filter. */
 +__LA_DECL int archive_read_set_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option string to both the format and the filter. */
 +__LA_DECL int archive_read_set_options(struct archive *_a,
 +			    const char *opts);
 +
 +/*-
 + * Convenience function to recreate the current entry (whose header
 + * has just been read) on disk.
 + *
 + * This does quite a bit more than just copy data to disk. It also:
 + *  - Creates intermediate directories as required.
 + *  - Manages directory permissions:  non-writable directories will
 + *    be initially created with write permission enabled; when the
 + *    archive is closed, dir permissions are edited to the values specified
 + *    in the archive.
 + *  - Checks hardlinks:  hardlinks will not be extracted unless the
 + *    linked-to file was also extracted within the same session. (TODO)
 + */
 +
 +/* The "flags" argument selects optional behavior, 'OR' the flags you want. */
 +
 +/* Default: Do not try to set owner/group. */
 +#define	ARCHIVE_EXTRACT_OWNER			(0x0001)
 +/* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */
 +#define	ARCHIVE_EXTRACT_PERM			(0x0002)
 +/* Default: Do not restore mtime/atime. */
 +#define	ARCHIVE_EXTRACT_TIME			(0x0004)
 +/* Default: Replace existing files. */
 +#define	ARCHIVE_EXTRACT_NO_OVERWRITE 		(0x0008)
 +/* Default: Try create first, unlink only if create fails with EEXIST. */
 +#define	ARCHIVE_EXTRACT_UNLINK			(0x0010)
 +/* Default: Do not restore ACLs. */
 +#define	ARCHIVE_EXTRACT_ACL			(0x0020)
 +/* Default: Do not restore fflags. */
 +#define	ARCHIVE_EXTRACT_FFLAGS			(0x0040)
 +/* Default: Do not restore xattrs. */
 +#define	ARCHIVE_EXTRACT_XATTR 			(0x0080)
 +/* Default: Do not try to guard against extracts redirected by symlinks. */
 +/* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */
 +#define	ARCHIVE_EXTRACT_SECURE_SYMLINKS		(0x0100)
 +/* Default: Do not reject entries with '..' as path elements. */
 +#define	ARCHIVE_EXTRACT_SECURE_NODOTDOT		(0x0200)
 +/* Default: Create parent directories as needed. */
 +#define	ARCHIVE_EXTRACT_NO_AUTODIR		(0x0400)
 +/* Default: Overwrite files, even if one on disk is newer. */
 +#define	ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER	(0x0800)
 +/* Detect blocks of 0 and write holes instead. */
 +#define	ARCHIVE_EXTRACT_SPARSE			(0x1000)
 +/* Default: Do not restore Mac extended metadata. */
 +/* This has no effect except on Mac OS. */
 +#define	ARCHIVE_EXTRACT_MAC_METADATA		(0x2000)
 +
 +__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
 +		     int flags);
 +__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *,
 +		     struct archive * /* dest */);
 +__LA_DECL void	 archive_read_extract_set_progress_callback(struct archive *,
 +		     void (*_progress_func)(void *), void *_user_data);
 +
 +/* Record the dev/ino of a file that will not be written.  This is
 + * generally set to the dev/ino of the archive being read. */
 +__LA_DECL void		archive_read_extract_set_skip_file(struct archive *,
 +		     __LA_INT64_T, __LA_INT64_T);
 +
 +/* Close the file and release most resources. */
 +__LA_DECL int		 archive_read_close(struct archive *);
 +/* Release all resources and destroy the object. */
 +/* Note that archive_read_free will call archive_read_close for you. */
 +__LA_DECL int		 archive_read_free(struct archive *);
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +/* Synonym for archive_read_free() for backwards compatibility. */
 +__LA_DECL int		 archive_read_finish(struct archive *);
 +#endif
 +
 +/*-
 + * To create an archive:
 + *   1) Ask archive_write_new for an archive writer object.
 + *   2) Set any global properties.  In particular, you should set
 + *      the compression and format to use.
 + *   3) Call archive_write_open to open the file (most people
 + *       will use archive_write_open_file or archive_write_open_fd,
 + *       which provide convenient canned I/O callbacks for you).
 + *   4) For each entry:
 + *      - construct an appropriate struct archive_entry structure
 + *      - archive_write_header to write the header
 + *      - archive_write_data to write the entry data
 + *   5) archive_write_close to close the output
 + *   6) archive_write_free to cleanup the writer and release resources
 + */
 +__LA_DECL struct archive	*archive_write_new(void);
 +__LA_DECL int archive_write_set_bytes_per_block(struct archive *,
 +		     int bytes_per_block);
 +__LA_DECL int archive_write_get_bytes_per_block(struct archive *);
 +/* XXX This is badly misnamed; suggestions appreciated. XXX */
 +__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *,
 +		     int bytes_in_last_block);
 +__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *);
 +
 +/* The dev/ino of a file that won't be archived.  This is used
 + * to avoid recursively adding an archive to itself. */
 +__LA_DECL int archive_write_set_skip_file(struct archive *,
 +    __LA_INT64_T, __LA_INT64_T);
 +
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +__LA_DECL int archive_write_set_compression_bzip2(struct archive *);
 +__LA_DECL int archive_write_set_compression_compress(struct archive *);
 +__LA_DECL int archive_write_set_compression_gzip(struct archive *);
 +__LA_DECL int archive_write_set_compression_lzip(struct archive *);
 +__LA_DECL int archive_write_set_compression_lzma(struct archive *);
 +__LA_DECL int archive_write_set_compression_none(struct archive *);
 +__LA_DECL int archive_write_set_compression_program(struct archive *,
 +		     const char *cmd);
 +__LA_DECL int archive_write_set_compression_xz(struct archive *);
 +#endif
 +
 +__LA_DECL int archive_write_add_filter_bzip2(struct archive *);
 +__LA_DECL int archive_write_add_filter_compress(struct archive *);
 +__LA_DECL int archive_write_add_filter_gzip(struct archive *);
 +__LA_DECL int archive_write_add_filter_lzip(struct archive *);
 +__LA_DECL int archive_write_add_filter_lzma(struct archive *);
 +__LA_DECL int archive_write_add_filter_none(struct archive *);
 +__LA_DECL int archive_write_add_filter_program(struct archive *,
 +		     const char *cmd);
 +__LA_DECL int archive_write_add_filter_xz(struct archive *);
 +
 +
 +/* A convenience function to set the format based on the code or name. */
 +__LA_DECL int archive_write_set_format(struct archive *, int format_code);
 +__LA_DECL int archive_write_set_format_by_name(struct archive *,
 +		     const char *name);
 +/* To minimize link pollution, use one or more of the following. */
 +__LA_DECL int archive_write_set_format_7zip(struct archive *);
 +__LA_DECL int archive_write_set_format_ar_bsd(struct archive *);
 +__LA_DECL int archive_write_set_format_ar_svr4(struct archive *);
 +__LA_DECL int archive_write_set_format_cpio(struct archive *);
 +__LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
 +__LA_DECL int archive_write_set_format_gnutar(struct archive *);
 +__LA_DECL int archive_write_set_format_iso9660(struct archive *);
 +__LA_DECL int archive_write_set_format_mtree(struct archive *);
 +/* TODO: int archive_write_set_format_old_tar(struct archive *); */
 +__LA_DECL int archive_write_set_format_pax(struct archive *);
 +__LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
 +__LA_DECL int archive_write_set_format_shar(struct archive *);
 +__LA_DECL int archive_write_set_format_shar_dump(struct archive *);
 +__LA_DECL int archive_write_set_format_ustar(struct archive *);
 +__LA_DECL int archive_write_set_format_xar(struct archive *);
 +__LA_DECL int archive_write_set_format_zip(struct archive *);
 +__LA_DECL int archive_write_open(struct archive *, void *,
 +		     archive_open_callback *, archive_write_callback *,
 +		     archive_close_callback *);
 +__LA_DECL int archive_write_open_fd(struct archive *, int _fd);
 +__LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
 +__LA_DECL int archive_write_open_filename_w(struct archive *,
 +		     const wchar_t *_file);
 +/* A deprecated synonym for archive_write_open_filename() */
 +__LA_DECL int archive_write_open_file(struct archive *, const char *_file);
 +__LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
 +/* _buffSize is the size of the buffer, _used refers to a variable that
 + * will be updated after each write into the buffer. */
 +__LA_DECL int archive_write_open_memory(struct archive *,
 +			void *_buffer, size_t _buffSize, size_t *_used);
 +
 +/*
 + * Note that the library will truncate writes beyond the size provided
 + * to archive_write_header or pad if the provided data is short.
 + */
 +__LA_DECL int archive_write_header(struct archive *,
 +		     struct archive_entry *);
 +__LA_DECL __LA_SSIZE_T	archive_write_data(struct archive *,
 +			    const void *, size_t);
 +
 +/* This interface is currently only available for archive_write_disk handles.  */
 +__LA_DECL __LA_SSIZE_T	 archive_write_data_block(struct archive *,
 +				    const void *, size_t, __LA_INT64_T);
 +
 +__LA_DECL int		 archive_write_finish_entry(struct archive *);
 +__LA_DECL int		 archive_write_close(struct archive *);
 +/* This can fail if the archive wasn't already closed, in which case
 + * archive_write_free() will implicitly call archive_write_close(). */
 +__LA_DECL int		 archive_write_free(struct archive *);
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +/* Synonym for archive_write_free() for backwards compatibility. */
 +__LA_DECL int		 archive_write_finish(struct archive *);
 +#endif
 +
 +/*
 + * Set write options.
 + */
 +/* Apply option to the format only. */
 +__LA_DECL int archive_write_set_format_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option to the filter only. */
 +__LA_DECL int archive_write_set_filter_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option to both the format and the filter. */
 +__LA_DECL int archive_write_set_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option string to both the format and the filter. */
 +__LA_DECL int archive_write_set_options(struct archive *_a,
 +			    const char *opts);
 +
 +/*-
 + * ARCHIVE_WRITE_DISK API
 + *
 + * To create objects on disk:
 + *   1) Ask archive_write_disk_new for a new archive_write_disk object.
 + *   2) Set any global properties.  In particular, you probably
 + *      want to set the options.
 + *   3) For each entry:
 + *      - construct an appropriate struct archive_entry structure
 + *      - archive_write_header to create the file/dir/etc on disk
 + *      - archive_write_data to write the entry data
 + *   4) archive_write_free to cleanup the writer and release resources
 + *
 + * In particular, you can use this in conjunction with archive_read()
 + * to pull entries out of an archive and create them on disk.
 + */
 +__LA_DECL struct archive	*archive_write_disk_new(void);
 +/* This file will not be overwritten. */
 +__LA_DECL int archive_write_disk_set_skip_file(struct archive *,
 +    __LA_INT64_T, __LA_INT64_T);
 +/* Set flags to control how the next item gets created.
 + * This accepts a bitmask of ARCHIVE_EXTRACT_XXX flags defined above. */
 +__LA_DECL int		 archive_write_disk_set_options(struct archive *,
 +		     int flags);
 +/*
 + * The lookup functions are given uname/uid (or gname/gid) pairs and
 + * return a uid (gid) suitable for this system.  These are used for
 + * restoring ownership and for setting ACLs.  The default functions
 + * are naive, they just return the uid/gid.  These are small, so reasonable
 + * for applications that don't need to preserve ownership; they
 + * are probably also appropriate for applications that are doing
 + * same-system backup and restore.
 + */
 +/*
 + * The "standard" lookup functions use common system calls to lookup
 + * the uname/gname, falling back to the uid/gid if the names can't be
 + * found.  They cache lookups and are reasonably fast, but can be very
 + * large, so they are not used unless you ask for them.  In
 + * particular, these match the specifications of POSIX "pax" and old
 + * POSIX "tar".
 + */
 +__LA_DECL int	 archive_write_disk_set_standard_lookup(struct archive *);
 +/*
 + * If neither the default (naive) nor the standard (big) functions suit
 + * your needs, you can write your own and register them.  Be sure to
 + * include a cleanup function if you have allocated private data.
 + */
 +__LA_DECL int archive_write_disk_set_group_lookup(struct archive *,
 +    void * /* private_data */,
 +    __LA_INT64_T (*)(void *, const char *, __LA_INT64_T),
 +    void (* /* cleanup */)(void *));
 +__LA_DECL int archive_write_disk_set_user_lookup(struct archive *,
 +    void * /* private_data */,
 +    __LA_INT64_T (*)(void *, const char *, __LA_INT64_T),
 +    void (* /* cleanup */)(void *));
 +__LA_DECL __LA_INT64_T archive_write_disk_gid(struct archive *, const char *, __LA_INT64_T);
 +__LA_DECL __LA_INT64_T archive_write_disk_uid(struct archive *, const char *, __LA_INT64_T);
 +
 +/*
 + * ARCHIVE_READ_DISK API
 + *
 + * This is still evolving and somewhat experimental.
 + */
 +__LA_DECL struct archive *archive_read_disk_new(void);
 +/* The names for symlink modes here correspond to an old BSD
 + * command-line argument convention: -L, -P, -H */
 +/* Follow all symlinks. */
 +__LA_DECL int archive_read_disk_set_symlink_logical(struct archive *);
 +/* Follow no symlinks. */
 +__LA_DECL int archive_read_disk_set_symlink_physical(struct archive *);
 +/* Follow symlink initially, then not. */
 +__LA_DECL int archive_read_disk_set_symlink_hybrid(struct archive *);
 +/* TODO: Handle Linux stat32/stat64 ugliness. <sigh> */
 +__LA_DECL int archive_read_disk_entry_from_file(struct archive *,
 +    struct archive_entry *, int /* fd */, const struct stat *);
 +/* Look up gname for gid or uname for uid. */
 +/* Default implementations are very, very stupid. */
 +__LA_DECL const char *archive_read_disk_gname(struct archive *, __LA_INT64_T);
 +__LA_DECL const char *archive_read_disk_uname(struct archive *, __LA_INT64_T);
 +/* "Standard" implementation uses getpwuid_r, getgrgid_r and caches the
 + * results for performance. */
 +__LA_DECL int	archive_read_disk_set_standard_lookup(struct archive *);
 +/* You can install your own lookups if you like. */
 +__LA_DECL int	archive_read_disk_set_gname_lookup(struct archive *,
 +    void * /* private_data */,
 +    const char *(* /* lookup_fn */)(void *, __LA_INT64_T),
 +    void (* /* cleanup_fn */)(void *));
 +__LA_DECL int	archive_read_disk_set_uname_lookup(struct archive *,
 +    void * /* private_data */,
 +    const char *(* /* lookup_fn */)(void *, __LA_INT64_T),
 +    void (* /* cleanup_fn */)(void *));
 +/* Start traversal. */
 +__LA_DECL int	archive_read_disk_open(struct archive *, const char *);
 +__LA_DECL int	archive_read_disk_open_w(struct archive *, const wchar_t *);
 +/*
 + * Request that current entry be visited.  If you invoke it on every
 + * directory, you'll get a physical traversal.  This is ignored if the
 + * current entry isn't a directory or a link to a directory.  So, if
 + * you invoke this on every returned path, you'll get a full logical
 + * traversal.
 + */
 +__LA_DECL int	archive_read_disk_descend(struct archive *);
 +__LA_DECL int	archive_read_disk_current_filesystem(struct archive *);
 +__LA_DECL int	archive_read_disk_current_filesystem_is_synthetic(struct archive *);
 +__LA_DECL int	archive_read_disk_current_filesystem_is_remote(struct archive *);
 +/* Request that the access time of the entry visited by travesal be restored. */
 +__LA_DECL int  archive_read_disk_set_atime_restored(struct archive *);
 +
 +/*
 + * Accessor functions to read/set various information in
 + * the struct archive object:
 + */
 +
 +/* Number of filters in the current filter pipeline. */
 +/* Filter #0 is the one closest to the format, -1 is a synonym for the
 + * last filter, which is always the pseudo-filter that wraps the
 + * client callbacks. */
 +__LA_DECL int		 archive_filter_count(struct archive *);
 +__LA_DECL __LA_INT64_T	 archive_filter_bytes(struct archive *, int);
 +__LA_DECL int		 archive_filter_code(struct archive *, int);
 +__LA_DECL const char *	 archive_filter_name(struct archive *, int);
 +
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +/* These don't properly handle multiple filters, so are deprecated and
 + * will eventually be removed. */
 +/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */
 +__LA_DECL __LA_INT64_T	 archive_position_compressed(struct archive *);
 +/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */
 +__LA_DECL __LA_INT64_T	 archive_position_uncompressed(struct archive *);
 +/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
 +__LA_DECL const char	*archive_compression_name(struct archive *);
 +/* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */
 +__LA_DECL int		 archive_compression(struct archive *);
 +#endif
 +
 +__LA_DECL int		 archive_errno(struct archive *);
 +__LA_DECL const char	*archive_error_string(struct archive *);
 +__LA_DECL const char	*archive_format_name(struct archive *);
 +__LA_DECL int		 archive_format(struct archive *);
 +__LA_DECL void		 archive_clear_error(struct archive *);
 +__LA_DECL void		 archive_set_error(struct archive *, int _err,
 +			    const char *fmt, ...) __LA_PRINTF(3, 4);
 +__LA_DECL void		 archive_copy_error(struct archive *dest,
 +			    struct archive *src);
 +__LA_DECL int		 archive_file_count(struct archive *);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +/* These are meaningless outside of this header. */
 +#undef __LA_DECL
 +#undef __LA_GID_T
 +#undef __LA_UID_T
 +
 +/* These need to remain defined because they're used in the
 + * callback type definitions.  XXX Fix this.  This is ugly. XXX */
 +/* #undef __LA_INT64_T */
 +/* #undef __LA_SSIZE_T */
 +
 +#endif /* !ARCHIVE_H_INCLUDED */
diff --cc Utilities/cmlibarchive/libarchive/archive_entry.h
index c85cf44,0000000..9c44e25
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry.h
+++ b/Utilities/cmlibarchive/libarchive/archive_entry.h
@@@ -1,620 -1,0 +1,620 @@@
 +/*-
 + * Copyright (c) 2003-2008 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: head/lib/libarchive/archive_entry.h 201096 2009-12-28 02:41:27Z kientzle $
 + */
 +
 +#ifndef ARCHIVE_ENTRY_H_INCLUDED
 +#define	ARCHIVE_ENTRY_H_INCLUDED
 +
 +/* Note: Compiler will complain if this does not match archive.h! */
- #define	ARCHIVE_VERSION_NUMBER 3000001
++#define	ARCHIVE_VERSION_NUMBER 3000002
 +
 +/*
 + * Note: archive_entry.h is for use outside of libarchive; the
 + * configuration headers (config.h, archive_platform.h, etc.) are
 + * purely internal.  Do NOT use HAVE_XXX configuration macros to
 + * control the behavior of this header!  If you must conditionalize,
 + * use predefined compiler and/or platform macros.
 + */
 +
 +#include <sys/types.h>
 +#include <stddef.h>  /* for wchar_t */
 +#include <time.h>
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +#include <windows.h>
 +#endif
 +
 +/* Get appropriate definitions of standard POSIX-style types. */
 +/* These should match the types used in 'struct stat' */
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +#define	__LA_INT64_T	__int64
 +# if defined(__BORLANDC__)
 +#  define	__LA_UID_T	uid_t  /* Remove in libarchive 3.2 */
 +#  define	__LA_GID_T	gid_t  /* Remove in libarchive 3.2 */
 +#  define	__LA_DEV_T	dev_t
 +#  define	__LA_MODE_T	mode_t
 +# else
 +#  define	__LA_UID_T	short  /* Remove in libarchive 3.2 */
 +#  define	__LA_GID_T	short  /* Remove in libarchive 3.2 */
 +#  define	__LA_DEV_T	unsigned int
 +#  define	__LA_MODE_T	unsigned short
 +# endif
 +#else
 +#include <unistd.h>
 +# if defined(_SCO_DS) || defined(__osf__)
 +#  define	__LA_INT64_T	long long
 +# else
 +#  define	__LA_INT64_T	int64_t
 +# endif
 +# define	__LA_UID_T	uid_t /* Remove in libarchive 3.2 */
 +# define	__LA_GID_T	gid_t /* Remove in libarchive 3.2 */
 +# define	__LA_DEV_T	dev_t
 +# define	__LA_MODE_T	mode_t
 +#endif
 +
 +/*
 + * Remove this for libarchive 3.2, since ino_t is no longer used.
 + */
 +#define	__LA_INO_T	ino_t
 +
 +
 +/*
 + * On Windows, define LIBARCHIVE_STATIC if you're building or using a
 + * .lib.  The default here assumes you're building a DLL.  Only
 + * libarchive source should ever define __LIBARCHIVE_BUILD.
 + */
 +#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC)
 +# ifdef __LIBARCHIVE_BUILD
 +#  ifdef __GNUC__
 +#   define __LA_DECL	__attribute__((dllexport)) extern
 +#  else
 +#   define __LA_DECL	__declspec(dllexport)
 +#  endif
 +# else
 +#  ifdef __GNUC__
 +#   define __LA_DECL
 +#  else
 +#   define __LA_DECL	__declspec(dllimport)
 +#  endif
 +# endif
 +#else
 +/* Static libraries on all platforms and shared libraries on non-Windows. */
 +# define __LA_DECL
 +#endif
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/*
 + * Description of an archive entry.
 + *
 + * You can think of this as "struct stat" with some text fields added in.
 + *
 + * TODO: Add "comment", "charset", and possibly other entries that are
 + * supported by "pax interchange" format.  However, GNU, ustar, cpio,
 + * and other variants don't support these features, so they're not an
 + * excruciatingly high priority right now.
 + *
 + * TODO: "pax interchange" format allows essentially arbitrary
 + * key/value attributes to be attached to any entry.  Supporting
 + * such extensions may make this library useful for special
 + * applications (e.g., a package manager could attach special
 + * package-management attributes to each entry).
 + */
 +struct archive;
 +struct archive_entry;
 +
 +/*
 + * File-type constants.  These are returned from archive_entry_filetype()
 + * and passed to archive_entry_set_filetype().
 + *
 + * These values match S_XXX defines on every platform I've checked,
 + * including Windows, AIX, Linux, Solaris, and BSD.  They're
 + * (re)defined here because platforms generally don't define the ones
 + * they don't support.  For example, Windows doesn't define S_IFLNK or
 + * S_IFBLK.  Instead of having a mass of conditional logic and system
 + * checks to define any S_XXX values that aren't supported locally,
 + * I've just defined a new set of such constants so that
 + * libarchive-based applications can manipulate and identify archive
 + * entries properly even if the hosting platform can't store them on
 + * disk.
 + *
 + * These values are also used directly within some portable formats,
 + * such as cpio.  If you find a platform that varies from these, the
 + * correct solution is to leave these alone and translate from these
 + * portable values to platform-native values when entries are read from
 + * or written to disk.
 + */
 +#define AE_IFMT		((__LA_MODE_T)0170000)
 +#define AE_IFREG	((__LA_MODE_T)0100000)
 +#define AE_IFLNK	((__LA_MODE_T)0120000)
 +#define AE_IFSOCK	((__LA_MODE_T)0140000)
 +#define AE_IFCHR	((__LA_MODE_T)0020000)
 +#define AE_IFBLK	((__LA_MODE_T)0060000)
 +#define AE_IFDIR	((__LA_MODE_T)0040000)
 +#define AE_IFIFO	((__LA_MODE_T)0010000)
 +
 +/*
 + * Basic object manipulation
 + */
 +
 +__LA_DECL struct archive_entry	*archive_entry_clear(struct archive_entry *);
 +/* The 'clone' function does a deep copy; all of the strings are copied too. */
 +__LA_DECL struct archive_entry	*archive_entry_clone(struct archive_entry *);
 +__LA_DECL void			 archive_entry_free(struct archive_entry *);
 +__LA_DECL struct archive_entry	*archive_entry_new(void);
 +
 +/*
 + * This form of archive_entry_new2() will pull character-set
 + * conversion information from the specified archive handle.  The
 + * older archive_entry_new(void) form is equivalent to calling
 + * archive_entry_new2(NULL) and will result in the use of an internal
 + * default character-set conversion.
 + */
 +__LA_DECL struct archive_entry	*archive_entry_new2(struct archive *);
 +
 +/*
 + * Retrieve fields from an archive_entry.
 + *
 + * There are a number of implicit conversions among these fields.  For
 + * example, if a regular string field is set and you read the _w wide
 + * character field, the entry will implicitly convert narrow-to-wide
 + * using the current locale.  Similarly, dev values are automatically
 + * updated when you write devmajor or devminor and vice versa.
 + *
 + * In addition, fields can be "set" or "unset."  Unset string fields
 + * return NULL, non-string fields have _is_set() functions to test
 + * whether they've been set.  You can "unset" a string field by
 + * assigning NULL; non-string fields have _unset() functions to
 + * unset them.
 + *
 + * Note: There is one ambiguity in the above; string fields will
 + * also return NULL when implicit character set conversions fail.
 + * This is usually what you want.
 + */
 +__LA_DECL time_t	 archive_entry_atime(struct archive_entry *);
 +__LA_DECL long		 archive_entry_atime_nsec(struct archive_entry *);
 +__LA_DECL int		 archive_entry_atime_is_set(struct archive_entry *);
 +__LA_DECL time_t	 archive_entry_birthtime(struct archive_entry *);
 +__LA_DECL long		 archive_entry_birthtime_nsec(struct archive_entry *);
 +__LA_DECL int		 archive_entry_birthtime_is_set(struct archive_entry *);
 +__LA_DECL time_t	 archive_entry_ctime(struct archive_entry *);
 +__LA_DECL long		 archive_entry_ctime_nsec(struct archive_entry *);
 +__LA_DECL int		 archive_entry_ctime_is_set(struct archive_entry *);
 +__LA_DECL dev_t		 archive_entry_dev(struct archive_entry *);
 +__LA_DECL int		 archive_entry_dev_is_set(struct archive_entry *);
 +__LA_DECL dev_t		 archive_entry_devmajor(struct archive_entry *);
 +__LA_DECL dev_t		 archive_entry_devminor(struct archive_entry *);
 +__LA_DECL __LA_MODE_T	 archive_entry_filetype(struct archive_entry *);
 +__LA_DECL void		 archive_entry_fflags(struct archive_entry *,
 +			    unsigned long * /* set */,
 +			    unsigned long * /* clear */);
 +__LA_DECL const char	*archive_entry_fflags_text(struct archive_entry *);
 +__LA_DECL __LA_INT64_T	 archive_entry_gid(struct archive_entry *);
 +__LA_DECL const char	*archive_entry_gname(struct archive_entry *);
 +__LA_DECL const wchar_t	*archive_entry_gname_w(struct archive_entry *);
 +__LA_DECL const char	*archive_entry_hardlink(struct archive_entry *);
 +__LA_DECL const wchar_t	*archive_entry_hardlink_w(struct archive_entry *);
 +__LA_DECL __LA_INT64_T	 archive_entry_ino(struct archive_entry *);
 +__LA_DECL __LA_INT64_T	 archive_entry_ino64(struct archive_entry *);
 +__LA_DECL int		 archive_entry_ino_is_set(struct archive_entry *);
 +__LA_DECL __LA_MODE_T	 archive_entry_mode(struct archive_entry *);
 +__LA_DECL time_t	 archive_entry_mtime(struct archive_entry *);
 +__LA_DECL long		 archive_entry_mtime_nsec(struct archive_entry *);
 +__LA_DECL int		 archive_entry_mtime_is_set(struct archive_entry *);
 +__LA_DECL unsigned int	 archive_entry_nlink(struct archive_entry *);
 +__LA_DECL const char	*archive_entry_pathname(struct archive_entry *);
 +__LA_DECL const wchar_t	*archive_entry_pathname_w(struct archive_entry *);
 +__LA_DECL __LA_MODE_T	 archive_entry_perm(struct archive_entry *);
 +__LA_DECL dev_t		 archive_entry_rdev(struct archive_entry *);
 +__LA_DECL dev_t		 archive_entry_rdevmajor(struct archive_entry *);
 +__LA_DECL dev_t		 archive_entry_rdevminor(struct archive_entry *);
 +__LA_DECL const char	*archive_entry_sourcepath(struct archive_entry *);
 +__LA_DECL const wchar_t	*archive_entry_sourcepath_w(struct archive_entry *);
 +__LA_DECL __LA_INT64_T	 archive_entry_size(struct archive_entry *);
 +__LA_DECL int		 archive_entry_size_is_set(struct archive_entry *);
 +__LA_DECL const char	*archive_entry_strmode(struct archive_entry *);
 +__LA_DECL const char	*archive_entry_symlink(struct archive_entry *);
 +__LA_DECL const wchar_t	*archive_entry_symlink_w(struct archive_entry *);
 +__LA_DECL __LA_INT64_T	 archive_entry_uid(struct archive_entry *);
 +__LA_DECL const char	*archive_entry_uname(struct archive_entry *);
 +__LA_DECL const wchar_t	*archive_entry_uname_w(struct archive_entry *);
 +
 +/*
 + * Set fields in an archive_entry.
 + *
 + * Note: Before libarchive 2.4, there were 'set' and 'copy' versions
 + * of the string setters.  'copy' copied the actual string, 'set' just
 + * stored the pointer.  In libarchive 2.4 and later, strings are
 + * always copied.
 + */
 +
 +__LA_DECL void	archive_entry_set_atime(struct archive_entry *, time_t, long);
 +__LA_DECL void  archive_entry_unset_atime(struct archive_entry *);
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *);
 +#endif
 +__LA_DECL void	archive_entry_set_birthtime(struct archive_entry *, time_t, long);
 +__LA_DECL void  archive_entry_unset_birthtime(struct archive_entry *);
 +__LA_DECL void	archive_entry_set_ctime(struct archive_entry *, time_t, long);
 +__LA_DECL void  archive_entry_unset_ctime(struct archive_entry *);
 +__LA_DECL void	archive_entry_set_dev(struct archive_entry *, dev_t);
 +__LA_DECL void	archive_entry_set_devmajor(struct archive_entry *, dev_t);
 +__LA_DECL void	archive_entry_set_devminor(struct archive_entry *, dev_t);
 +__LA_DECL void	archive_entry_set_filetype(struct archive_entry *, unsigned int);
 +__LA_DECL void	archive_entry_set_fflags(struct archive_entry *,
 +	    unsigned long /* set */, unsigned long /* clear */);
 +/* Returns pointer to start of first invalid token, or NULL if none. */
 +/* Note that all recognized tokens are processed, regardless. */
 +__LA_DECL const char *archive_entry_copy_fflags_text(struct archive_entry *,
 +	    const char *);
 +__LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *,
 +	    const wchar_t *);
 +__LA_DECL void	archive_entry_set_gid(struct archive_entry *, __LA_INT64_T);
 +__LA_DECL void	archive_entry_set_gname(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_gname(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);
 +__LA_DECL int	archive_entry_update_gname_utf8(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_set_hardlink(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_hardlink(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
 +__LA_DECL int	archive_entry_update_hardlink_utf8(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_set_ino(struct archive_entry *, __LA_INT64_T);
 +__LA_DECL void	archive_entry_set_ino64(struct archive_entry *, __LA_INT64_T);
 +__LA_DECL void	archive_entry_set_link(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_link(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_link_w(struct archive_entry *, const wchar_t *);
 +__LA_DECL int	archive_entry_update_link_utf8(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_set_mode(struct archive_entry *, __LA_MODE_T);
 +__LA_DECL void	archive_entry_set_mtime(struct archive_entry *, time_t, long);
 +__LA_DECL void  archive_entry_unset_mtime(struct archive_entry *);
 +__LA_DECL void	archive_entry_set_nlink(struct archive_entry *, unsigned int);
 +__LA_DECL void	archive_entry_set_pathname(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_pathname(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);
 +__LA_DECL int	archive_entry_update_pathname_utf8(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_set_perm(struct archive_entry *, __LA_MODE_T);
 +__LA_DECL void	archive_entry_set_rdev(struct archive_entry *, dev_t);
 +__LA_DECL void	archive_entry_set_rdevmajor(struct archive_entry *, dev_t);
 +__LA_DECL void	archive_entry_set_rdevminor(struct archive_entry *, dev_t);
 +__LA_DECL void	archive_entry_set_size(struct archive_entry *, __LA_INT64_T);
 +__LA_DECL void	archive_entry_unset_size(struct archive_entry *);
 +__LA_DECL void	archive_entry_copy_sourcepath(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_sourcepath_w(struct archive_entry *, const wchar_t *);
 +__LA_DECL void	archive_entry_set_symlink(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_symlink(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *);
 +__LA_DECL int	archive_entry_update_symlink_utf8(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_set_uid(struct archive_entry *, __LA_INT64_T);
 +__LA_DECL void	archive_entry_set_uname(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_uname(struct archive_entry *, const char *);
 +__LA_DECL void	archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);
 +__LA_DECL int	archive_entry_update_uname_utf8(struct archive_entry *, const char *);
 +/*
 + * Routines to bulk copy fields to/from a platform-native "struct
 + * stat."  Libarchive used to just store a struct stat inside of each
 + * archive_entry object, but this created issues when trying to
 + * manipulate archives on systems different than the ones they were
 + * created on.
 + *
 + * TODO: On Linux, provide both stat32 and stat64 versions of these functions.
 + */
 +__LA_DECL const struct stat	*archive_entry_stat(struct archive_entry *);
 +__LA_DECL void	archive_entry_copy_stat(struct archive_entry *, const struct stat *);
 +
 +/*
 + * Storage for Mac OS-specific AppleDouble metadata information.
 + * Apple-format tar files store a separate binary blob containing
 + * encoded metadata with ACL, extended attributes, etc.
 + * This provides a place to store that blob.
 + */
 +
 +__LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t *);
 +__LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t);
 +
 +/*
 + * ACL routines.  This used to simply store and return text-format ACL
 + * strings, but that proved insufficient for a number of reasons:
 + *   = clients need control over uname/uid and gname/gid mappings
 + *   = there are many different ACL text formats
 + *   = would like to be able to read/convert archives containing ACLs
 + *     on platforms that lack ACL libraries
 + *
 + *  This last point, in particular, forces me to implement a reasonably
 + *  complete set of ACL support routines.
 + */
 +
 +/*
 + * Permission bits.
 + */
 +#define	ARCHIVE_ENTRY_ACL_EXECUTE             0x00000001
 +#define	ARCHIVE_ENTRY_ACL_WRITE               0x00000002
 +#define	ARCHIVE_ENTRY_ACL_READ                0x00000004
 +#define	ARCHIVE_ENTRY_ACL_READ_DATA           0x00000008
 +#define	ARCHIVE_ENTRY_ACL_LIST_DIRECTORY      0x00000008
 +#define	ARCHIVE_ENTRY_ACL_WRITE_DATA          0x00000010
 +#define	ARCHIVE_ENTRY_ACL_ADD_FILE            0x00000010
 +#define	ARCHIVE_ENTRY_ACL_APPEND_DATA         0x00000020
 +#define	ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY    0x00000020
 +#define	ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS    0x00000040
 +#define	ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS   0x00000080
 +#define	ARCHIVE_ENTRY_ACL_DELETE_CHILD        0x00000100
 +#define	ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES     0x00000200
 +#define	ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES    0x00000400
 +#define	ARCHIVE_ENTRY_ACL_DELETE              0x00000800
 +#define	ARCHIVE_ENTRY_ACL_READ_ACL            0x00001000
 +#define	ARCHIVE_ENTRY_ACL_WRITE_ACL           0x00002000
 +#define	ARCHIVE_ENTRY_ACL_WRITE_OWNER         0x00004000
 +#define	ARCHIVE_ENTRY_ACL_SYNCHRONIZE         0x00008000
 +
 +#define	ARCHIVE_ENTRY_ACL_PERMS_POSIX1E			\
 +	(ARCHIVE_ENTRY_ACL_EXECUTE			\
 +	    | ARCHIVE_ENTRY_ACL_WRITE			\
 +	    | ARCHIVE_ENTRY_ACL_READ)
 +
 +#define ARCHIVE_ENTRY_ACL_PERMS_NFS4			\
 +	(ARCHIVE_ENTRY_ACL_EXECUTE			\
 +	    | ARCHIVE_ENTRY_ACL_READ_DATA		\
 +	    | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY 		\
 +	    | ARCHIVE_ENTRY_ACL_WRITE_DATA		\
 +	    | ARCHIVE_ENTRY_ACL_ADD_FILE		\
 +	    | ARCHIVE_ENTRY_ACL_APPEND_DATA		\
 +	    | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY	\
 +	    | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS	\
 +	    | ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS	\
 +	    | ARCHIVE_ENTRY_ACL_DELETE_CHILD		\
 +	    | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES		\
 +	    | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES	\
 +	    | ARCHIVE_ENTRY_ACL_DELETE			\
 +	    | ARCHIVE_ENTRY_ACL_READ_ACL		\
 +	    | ARCHIVE_ENTRY_ACL_WRITE_ACL		\
 +	    | ARCHIVE_ENTRY_ACL_WRITE_OWNER		\
 +	    | ARCHIVE_ENTRY_ACL_SYNCHRONIZE)
 +
 +/*
 + * Inheritance values (NFS4 ACLs only); included in permset.
 + */
 +#define	ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT                0x02000000
 +#define	ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT           0x04000000
 +#define	ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT        0x08000000
 +#define	ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY                0x10000000
 +#define	ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS           0x20000000
 +#define	ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS               0x40000000
 +
 +#define	ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4			\
 +	(ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT			\
 +	    | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT		\
 +	    | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT	\
 +	    | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY		\
 +	    | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS		\
 +	    | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS)
 +
 +/* We need to be able to specify combinations of these. */
 +#define	ARCHIVE_ENTRY_ACL_TYPE_ACCESS	256  /* POSIX.1e only */
 +#define	ARCHIVE_ENTRY_ACL_TYPE_DEFAULT	512  /* POSIX.1e only */
 +#define	ARCHIVE_ENTRY_ACL_TYPE_ALLOW	1024 /* NFS4 only */
 +#define	ARCHIVE_ENTRY_ACL_TYPE_DENY	2048 /* NFS4 only */
 +#define	ARCHIVE_ENTRY_ACL_TYPE_AUDIT	4096 /* NFS4 only */
 +#define	ARCHIVE_ENTRY_ACL_TYPE_ALARM	8192 /* NFS4 only */
 +#define	ARCHIVE_ENTRY_ACL_TYPE_POSIX1E	(ARCHIVE_ENTRY_ACL_TYPE_ACCESS \
 +	    | ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
 +#define	ARCHIVE_ENTRY_ACL_TYPE_NFS4	(ARCHIVE_ENTRY_ACL_TYPE_ALLOW \
 +	    | ARCHIVE_ENTRY_ACL_TYPE_DENY \
 +	    | ARCHIVE_ENTRY_ACL_TYPE_AUDIT \
 +	    | ARCHIVE_ENTRY_ACL_TYPE_ALARM)
 +
 +/* Tag values mimic POSIX.1e */
 +#define	ARCHIVE_ENTRY_ACL_USER		10001	/* Specified user. */
 +#define	ARCHIVE_ENTRY_ACL_USER_OBJ 	10002	/* User who owns the file. */
 +#define	ARCHIVE_ENTRY_ACL_GROUP		10003	/* Specified group. */
 +#define	ARCHIVE_ENTRY_ACL_GROUP_OBJ	10004	/* Group who owns the file. */
 +#define	ARCHIVE_ENTRY_ACL_MASK		10005	/* Modify group access (POSIX.1e only) */
 +#define	ARCHIVE_ENTRY_ACL_OTHER		10006	/* Public (POSIX.1e only) */
 +#define	ARCHIVE_ENTRY_ACL_EVERYONE	10107   /* Everyone (NFS4 only) */
 +
 +/*
 + * Set the ACL by clearing it and adding entries one at a time.
 + * Unlike the POSIX.1e ACL routines, you must specify the type
 + * (access/default) for each entry.  Internally, the ACL data is just
 + * a soup of entries.  API calls here allow you to retrieve just the
 + * entries of interest.  This design (which goes against the spirit of
 + * POSIX.1e) is useful for handling archive formats that combine
 + * default and access information in a single ACL list.
 + */
 +__LA_DECL void	 archive_entry_acl_clear(struct archive_entry *);
 +__LA_DECL int	 archive_entry_acl_add_entry(struct archive_entry *,
 +	    int /* type */, int /* permset */, int /* tag */,
 +	    int /* qual */, const char * /* name */);
 +__LA_DECL int	 archive_entry_acl_add_entry_w(struct archive_entry *,
 +	    int /* type */, int /* permset */, int /* tag */,
 +	    int /* qual */, const wchar_t * /* name */);
 +
 +/*
 + * To retrieve the ACL, first "reset", then repeatedly ask for the
 + * "next" entry.  The want_type parameter allows you to request only
 + * certain types of entries.
 + */
 +__LA_DECL int	 archive_entry_acl_reset(struct archive_entry *, int /* want_type */);
 +__LA_DECL int	 archive_entry_acl_next(struct archive_entry *, int /* want_type */,
 +	    int * /* type */, int * /* permset */, int * /* tag */,
 +	    int * /* qual */, const char ** /* name */);
 +__LA_DECL int	 archive_entry_acl_next_w(struct archive_entry *, int /* want_type */,
 +	    int * /* type */, int * /* permset */, int * /* tag */,
 +	    int * /* qual */, const wchar_t ** /* name */);
 +
 +/*
 + * Construct a text-format ACL.  The flags argument is a bitmask that
 + * can include any of the following:
 + *
 + * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include POSIX.1e "access" entries.
 + * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include POSIX.1e "default" entries.
 + * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - Include NFS4 entries.
 + * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
 + *    each ACL entry.  ('star' introduced this for POSIX.1e, this flag
 + *    also applies to NFS4.)
 + * ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
 + *    default ACL entry, as used in old Solaris ACLs.
 + */
 +#define	ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID	1024
 +#define	ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT	2048
 +__LA_DECL const wchar_t	*archive_entry_acl_text_w(struct archive_entry *,
 +		    int /* flags */);
 +__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
 +		    int /* flags */);
 +
 +/* Return a count of entries matching 'want_type' */
 +__LA_DECL int	 archive_entry_acl_count(struct archive_entry *, int /* want_type */);
 +
 +/* Return an opaque ACL object. */
 +/* There's not yet anything clients can actually do with this... */
 +struct archive_acl;
 +__LA_DECL struct archive_acl *archive_entry_acl(struct archive_entry *);
 +
 +/*
 + * extended attributes
 + */
 +
 +__LA_DECL void	 archive_entry_xattr_clear(struct archive_entry *);
 +__LA_DECL void	 archive_entry_xattr_add_entry(struct archive_entry *,
 +	    const char * /* name */, const void * /* value */,
 +	    size_t /* size */);
 +
 +/*
 + * To retrieve the xattr list, first "reset", then repeatedly ask for the
 + * "next" entry.
 + */
 +
 +__LA_DECL int	archive_entry_xattr_count(struct archive_entry *);
 +__LA_DECL int	archive_entry_xattr_reset(struct archive_entry *);
 +__LA_DECL int	archive_entry_xattr_next(struct archive_entry *,
 +	    const char ** /* name */, const void ** /* value */, size_t *);
 +
 +/*
 + * sparse
 + */
 +
 +__LA_DECL void	 archive_entry_sparse_clear(struct archive_entry *);
 +__LA_DECL void	 archive_entry_sparse_add_entry(struct archive_entry *,
 +	    __LA_INT64_T /* offset */, __LA_INT64_T /* length */);
 +
 +/*
 + * To retrieve the xattr list, first "reset", then repeatedly ask for the
 + * "next" entry.
 + */
 +
 +__LA_DECL int	archive_entry_sparse_count(struct archive_entry *);
 +__LA_DECL int	archive_entry_sparse_reset(struct archive_entry *);
 +__LA_DECL int	archive_entry_sparse_next(struct archive_entry *,
 +	    __LA_INT64_T * /* offset */, __LA_INT64_T * /* length */);
 +
 +/*
 + * Utility to match up hardlinks.
 + *
 + * The 'struct archive_entry_linkresolver' is a cache of archive entries
 + * for files with multiple links.  Here's how to use it:
 + *   1. Create a lookup object with archive_entry_linkresolver_new()
 + *   2. Tell it the archive format you're using.
 + *   3. Hand each archive_entry to archive_entry_linkify().
 + *      That function will return 0, 1, or 2 entries that should
 + *      be written.
 + *   4. Call archive_entry_linkify(resolver, NULL) until
 + *      no more entries are returned.
 + *   5. Call archive_entry_linkresolver_free(resolver) to free resources.
 + *
 + * The entries returned have their hardlink and size fields updated
 + * appropriately.  If an entry is passed in that does not refer to
 + * a file with multiple links, it is returned unchanged.  The intention
 + * is that you should be able to simply filter all entries through
 + * this machine.
 + *
 + * To make things more efficient, be sure that each entry has a valid
 + * nlinks value.  The hardlink cache uses this to track when all links
 + * have been found.  If the nlinks value is zero, it will keep every
 + * name in the cache indefinitely, which can use a lot of memory.
 + *
 + * Note that archive_entry_size() is reset to zero if the file
 + * body should not be written to the archive.  Pay attention!
 + */
 +struct archive_entry_linkresolver;
 +
 +/*
 + * There are three different strategies for marking hardlinks.
 + * The descriptions below name them after the best-known
 + * formats that rely on each strategy:
 + *
 + * "Old cpio" is the simplest, it always returns any entry unmodified.
 + *    As far as I know, only cpio formats use this.  Old cpio archives
 + *    store every link with the full body; the onus is on the dearchiver
 + *    to detect and properly link the files as they are restored.
 + * "tar" is also pretty simple; it caches a copy the first time it sees
 + *    any link.  Subsequent appearances are modified to be hardlink
 + *    references to the first one without any body.  Used by all tar
 + *    formats, although the newest tar formats permit the "old cpio" strategy
 + *    as well.  This strategy is very simple for the dearchiver,
 + *    and reasonably straightforward for the archiver.
 + * "new cpio" is trickier.  It stores the body only with the last
 + *    occurrence.  The complication is that we might not
 + *    see every link to a particular file in a single session, so
 + *    there's no easy way to know when we've seen the last occurrence.
 + *    The solution here is to queue one link until we see the next.
 + *    At the end of the session, you can enumerate any remaining
 + *    entries by calling archive_entry_linkify(NULL) and store those
 + *    bodies.  If you have a file with three links l1, l2, and l3,
 + *    you'll get the following behavior if you see all three links:
 + *           linkify(l1) => NULL   (the resolver stores l1 internally)
 + *           linkify(l2) => l1     (resolver stores l2, you write l1)
 + *           linkify(l3) => l2, l3 (all links seen, you can write both).
 + *    If you only see l1 and l2, you'll get this behavior:
 + *           linkify(l1) => NULL
 + *           linkify(l2) => l1
 + *           linkify(NULL) => l2   (at end, you retrieve remaining links)
 + *    As the name suggests, this strategy is used by newer cpio variants.
 + *    It's noticeably more complex for the archiver, slightly more complex
 + *    for the dearchiver than the tar strategy, but makes it straightforward
 + *    to restore a file using any link by simply continuing to scan until
 + *    you see a link that is stored with a body.  In contrast, the tar
 + *    strategy requires you to rescan the archive from the beginning to
 + *    correctly extract an arbitrary link.
 + */
 +
 +__LA_DECL struct archive_entry_linkresolver *archive_entry_linkresolver_new(void);
 +__LA_DECL void archive_entry_linkresolver_set_strategy(
 +	struct archive_entry_linkresolver *, int /* format_code */);
 +__LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *);
 +__LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *,
 +    struct archive_entry **, struct archive_entry **);
 +__LA_DECL struct archive_entry *archive_entry_partial_links(
 +    struct archive_entry_linkresolver *res, unsigned int *links);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +/* This is meaningless outside of this header. */
 +#undef __LA_DECL
 +
 +#endif /* !ARCHIVE_ENTRY_H_INCLUDED */
diff --cc Utilities/cmlibarchive/libarchive/archive_read.c
index 6d7f263,0000000..baf9dc4
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read.c
@@@ -1,1358 -1,0 +1,1342 @@@
 +/*-
 + * 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.
 + */
 +
 +/*
 + * This file contains the "essential" portions of the read API, that
 + * is, stuff that will probably always be used by any client that
 + * actually needs to read an archive.  Optional pieces have been, as
 + * far as possible, separated out into separate files to avoid
 + * needlessly bloating statically-linked clients.
 + */
 +
 +#include "archive_platform.h"
 +__FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:23Z 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_UNISTD_H
 +#include <unistd.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_entry.h"
 +#include "archive_private.h"
 +#include "archive_read_private.h"
 +
 +#define minimum(a, b) (a < b ? a : b)
 +
 +static int	choose_filters(struct archive_read *);
 +static int	choose_format(struct archive_read *);
 +static void	free_filters(struct archive_read *);
 +static int	close_filters(struct archive_read *);
 +static struct archive_vtable *archive_read_vtable(void);
 +static int64_t	_archive_filter_bytes(struct archive *, int);
 +static int	_archive_filter_code(struct archive *, int);
 +static const char *_archive_filter_name(struct archive *, int);
 +static int  _archive_filter_count(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_free(struct archive *);
 +static int	_archive_read_next_header(struct archive *,
 +		    struct archive_entry **);
 +static int	_archive_read_next_header2(struct archive *,
 +		    struct archive_entry *);
 +static int64_t  advance_file_pointer(struct archive_read_filter *, int64_t);
 +
 +static struct archive_vtable *
 +archive_read_vtable(void)
 +{
 +	static struct archive_vtable av;
 +	static int inited = 0;
 +
 +	if (!inited) {
 +		av.archive_filter_bytes = _archive_filter_bytes;
 +		av.archive_filter_code = _archive_filter_code;
 +		av.archive_filter_name = _archive_filter_name;
 +		av.archive_filter_count = _archive_filter_count;
 +		av.archive_read_data_block = _archive_read_data_block;
 +		av.archive_read_next_header = _archive_read_next_header;
 +		av.archive_read_next_header2 = _archive_read_next_header2;
 +		av.archive_free = _archive_read_free;
 +		av.archive_close = _archive_read_close;
 +		inited = 1;
 +	}
 +	return (&av);
 +}
 +
 +/*
 + * Allocate, initialize and return a struct archive object.
 + */
 +struct archive *
 +archive_read_new(void)
 +{
 +	struct archive_read *a;
 +
 +	a = (struct archive_read *)malloc(sizeof(*a));
 +	if (a == NULL)
 +		return (NULL);
 +	memset(a, 0, sizeof(*a));
 +	a->archive.magic = ARCHIVE_READ_MAGIC;
 +
 +	a->archive.state = ARCHIVE_STATE_NEW;
 +	a->entry = archive_entry_new2(&a->archive);
 +	a->archive.vtable = archive_read_vtable();
 +
 +	return (&a->archive);
 +}
 +
 +/*
 + * Record the do-not-extract-to file. This belongs in archive_read_extract.c.
 + */
 +void
 +archive_read_extract_set_skip_file(struct archive *_a, int64_t d, int64_t i)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +
 +	if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +		ARCHIVE_STATE_ANY, "archive_read_extract_set_skip_file"))
 +		return;
 +	a->skip_file_set = 1;
 +	a->skip_file_dev = d;
 +	a->skip_file_ino = i;
 +}
 +
 +/*
 + * Open the archive
 + */
 +int
 +archive_read_open(struct archive *a, void *client_data,
 +    archive_open_callback *client_opener, archive_read_callback *client_reader,
 +    archive_close_callback *client_closer)
 +{
 +	/* Old archive_read_open() is just a thin shell around
 +	 * archive_read_open1. */
 +	archive_read_set_open_callback(a, client_opener);
 +	archive_read_set_read_callback(a, client_reader);
 +	archive_read_set_close_callback(a, client_closer);
 +	archive_read_set_callback_data(a, client_data);
 +	return archive_read_open1(a);
 +}
 +
 +
 +int
 +archive_read_open2(struct archive *a, void *client_data,
 +    archive_open_callback *client_opener,
 +    archive_read_callback *client_reader,
 +    archive_skip_callback *client_skipper,
 +    archive_close_callback *client_closer)
 +{
 +	/* Old archive_read_open2() is just a thin shell around
 +	 * archive_read_open1. */
 +	archive_read_set_callback_data(a, client_data);
 +	archive_read_set_open_callback(a, client_opener);
 +	archive_read_set_read_callback(a, client_reader);
 +	archive_read_set_skip_callback(a, client_skipper);
 +	archive_read_set_close_callback(a, client_closer);
 +	return archive_read_open1(a);
 +}
 +
 +static ssize_t
 +client_read_proxy(struct archive_read_filter *self, const void **buff)
 +{
 +	ssize_t r;
 +	r = (self->archive->client.reader)(&self->archive->archive,
 +	    self->data, buff);
 +	return (r);
 +}
 +
 +static int64_t
 +client_skip_proxy(struct archive_read_filter *self, int64_t request)
 +{
 +	if (request < 0)
 +		__archive_errx(1, "Negative skip requested.");
 +	if (request == 0)
 +		return 0;
 +
 +	if (self->archive->client.skipper != NULL) {
 +		/* Seek requests over 1GiB are broken down into
 +		 * multiple seeks.  This avoids overflows when the
 +		 * requests get passed through 32-bit arguments. */
 +		int64_t skip_limit = (int64_t)1 << 30;
 +		int64_t total = 0;
 +		for (;;) {
 +			int64_t get, ask = request;
 +			if (ask > skip_limit)
 +				ask = skip_limit;
 +			get = (self->archive->client.skipper)(&self->archive->archive,
 +			    self->data, ask);
 +			if (get == 0)
 +				return (total);
 +			request -= get;
 +			total += get;
 +		}
 +		return total;
 +	} else if (self->archive->client.seeker != NULL
 +		&& request > 64 * 1024) {
 +		/* If the client provided a seeker but not a skipper,
 +		 * we can use the seeker to skip forward.
 +		 *
 +		 * Note: This isn't always a good idea.  The client
 +		 * skipper is allowed to skip by less than requested
 +		 * if it needs to maintain block alignment.  The
 +		 * seeker is not allowed to play such games, so using
 +		 * the seeker here may be a performance loss compared
 +		 * to just reading and discarding.  That's why we
 +		 * only do this for skips of over 64k.
 +		 */
 +		int64_t before = self->position;
 +		int64_t after = (self->archive->client.seeker)(&self->archive->archive,
 +		    self->data, request, SEEK_CUR);
 +		if (after != before + request)
 +			return ARCHIVE_FATAL;
 +		return after - before;
 +	}
 +	return 0;
 +}
 +
 +static int64_t
 +client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)
 +{
 +	/* DO NOT use the skipper here!  If we transparently handled
 +	 * forward seek here by using the skipper, that will break
 +	 * other libarchive code that assumes a successful forward
 +	 * seek means it can also seek backwards.
 +	 */
 +	if (self->archive->client.seeker == NULL)
 +		return (ARCHIVE_FAILED);
 +	return (self->archive->client.seeker)(&self->archive->archive,
 +	    self->data, offset, whence);
 +}
 +
 +static int
 +client_close_proxy(struct archive_read_filter *self)
 +{
 +	int r = ARCHIVE_OK;
 +
 +	if (self->archive->client.closer != NULL)
 +		r = (self->archive->client.closer)((struct archive *)self->archive,
 +		    self->data);
 +	return (r);
 +}
 +
 +int
 +archive_read_set_open_callback(struct archive *_a,
 +    archive_open_callback *client_opener)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_set_open_callback");
 +	a->client.opener = client_opener;
 +	return ARCHIVE_OK;
 +}
 +
 +int
 +archive_read_set_read_callback(struct archive *_a,
 +    archive_read_callback *client_reader)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_set_read_callback");
 +	a->client.reader = client_reader;
 +	return ARCHIVE_OK;
 +}
 +
 +int
 +archive_read_set_skip_callback(struct archive *_a,
 +    archive_skip_callback *client_skipper)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_set_skip_callback");
 +	a->client.skipper = client_skipper;
 +	return ARCHIVE_OK;
 +}
 +
 +int
 +archive_read_set_seek_callback(struct archive *_a,
 +    archive_seek_callback *client_seeker)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_set_seek_callback");
 +	a->client.seeker = client_seeker;
 +	return ARCHIVE_OK;
 +}
 +
 +int
 +archive_read_set_close_callback(struct archive *_a,
 +    archive_close_callback *client_closer)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_set_close_callback");
 +	a->client.closer = client_closer;
 +	return ARCHIVE_OK;
 +}
 +
 +int
 +archive_read_set_callback_data(struct archive *_a, void *client_data)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_set_callback_data");
 +	a->client.data = client_data;
 +	return ARCHIVE_OK;
 +}
 +
 +int
 +archive_read_open1(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct archive_read_filter *filter;
 +	int slot, e;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_open");
 +	archive_clear_error(&a->archive);
 +
 +	if (a->client.reader == NULL) {
 +		archive_set_error(&a->archive, EINVAL,
 +		    "No reader function provided to archive_read_open");
 +		a->archive.state = ARCHIVE_STATE_FATAL;
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Open data source. */
 +	if (a->client.opener != NULL) {
 +		e =(a->client.opener)(&a->archive, a->client.data);
 +		if (e != 0) {
 +			/* If the open failed, call the closer to clean up. */
 +			if (a->client.closer)
 +				(a->client.closer)(&a->archive, a->client.data);
 +			return (e);
 +		}
 +	}
 +
 +	filter = calloc(1, sizeof(*filter));
 +	if (filter == NULL)
 +		return (ARCHIVE_FATAL);
 +	filter->bidder = NULL;
 +	filter->upstream = NULL;
 +	filter->archive = a;
 +	filter->data = a->client.data;
 +	filter->read = client_read_proxy;
 +	filter->skip = client_skip_proxy;
 +	filter->seek = client_seek_proxy;
 +	filter->close = client_close_proxy;
 +	filter->name = "none";
 +	filter->code = ARCHIVE_COMPRESSION_NONE;
 +	a->filter = filter;
 +
 +	/* Build out the input pipeline. */
 +	e = choose_filters(a);
 +	if (e < ARCHIVE_WARN) {
 +		a->archive.state = ARCHIVE_STATE_FATAL;
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	slot = choose_format(a);
 +	if (slot < 0) {
 +		close_filters(a);
 +		a->archive.state = ARCHIVE_STATE_FATAL;
 +		return (ARCHIVE_FATAL);
 +	}
 +	a->format = &(a->formats[slot]);
 +
 +	a->archive.state = ARCHIVE_STATE_HEADER;
 +	return (e);
 +}
 +
 +/*
 + * Allow each registered stream transform to bid on whether
 + * it wants to handle this stream.  Repeat until we've finished
 + * building the pipeline.
 + */
 +static int
 +choose_filters(struct archive_read *a)
 +{
 +	int number_bidders, i, bid, best_bid;
 +	struct archive_read_filter_bidder *bidder, *best_bidder;
 +	struct archive_read_filter *filter;
 +	ssize_t avail;
 +	int r;
 +
 +	for (;;) {
 +		number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
 +
 +		best_bid = 0;
 +		best_bidder = NULL;
 +
 +		bidder = a->bidders;
 +		for (i = 0; i < number_bidders; i++, bidder++) {
 +			if (bidder->bid != NULL) {
 +				bid = (bidder->bid)(bidder, a->filter);
 +				if (bid > best_bid) {
 +					best_bid = bid;
 +					best_bidder = bidder;
 +				}
 +			}
 +		}
 +
 +		/* If no bidder, we're done. */
 +		if (best_bidder == NULL) {
 +			/* Verify the filter by asking it for some data. */
 +			__archive_read_filter_ahead(a->filter, 1, &avail);
 +			if (avail < 0) {
 +				close_filters(a);
 +				free_filters(a);
 +				return (ARCHIVE_FATAL);
 +			}
 +			a->archive.compression_name = a->filter->name;
 +			a->archive.compression_code = a->filter->code;
 +			return (ARCHIVE_OK);
 +		}
 +
 +		filter
 +		    = (struct archive_read_filter *)calloc(1, sizeof(*filter));
 +		if (filter == NULL)
 +			return (ARCHIVE_FATAL);
 +		filter->bidder = best_bidder;
 +		filter->archive = a;
 +		filter->upstream = a->filter;
 +		a->filter = filter;
 +		r = (best_bidder->init)(a->filter);
 +		if (r != ARCHIVE_OK) {
 +			close_filters(a);
 +			free_filters(a);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +}
 +
 +/*
 + * Read header of next entry.
 + */
 +static int
 +_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	int r1 = ARCHIVE_OK, r2;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
 +	    "archive_read_next_header");
 +
 +	archive_entry_clear(entry);
 +	archive_clear_error(&a->archive);
 +
 +	/*
 +	 * If client didn't consume entire data, skip any remainder
 +	 * (This is especially important for GNU incremental directories.)
 +	 */
 +	if (a->archive.state == ARCHIVE_STATE_DATA) {
 +		r1 = archive_read_data_skip(&a->archive);
 +		if (r1 == ARCHIVE_EOF)
 +			archive_set_error(&a->archive, EIO,
 +			    "Premature end-of-file.");
 +		if (r1 == ARCHIVE_EOF || r1 == ARCHIVE_FATAL) {
 +			a->archive.state = ARCHIVE_STATE_FATAL;
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	/* Record start-of-header offset in uncompressed stream. */
 +	a->header_position = a->filter->position;
 +
 +	++_a->file_count;
 +	r2 = (a->format->read_header)(a, entry);
 +
 +	/*
 +	 * 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 (r2) {
 +	case ARCHIVE_EOF:
 +		a->archive.state = ARCHIVE_STATE_EOF;
 +		--_a->file_count;/* Revert a file counter. */
 +		break;
 +	case ARCHIVE_OK:
 +		a->archive.state = ARCHIVE_STATE_DATA;
 +		break;
 +	case ARCHIVE_WARN:
 +		a->archive.state = ARCHIVE_STATE_DATA;
 +		break;
 +	case ARCHIVE_RETRY:
 +		break;
 +	case ARCHIVE_FATAL:
 +		a->archive.state = ARCHIVE_STATE_FATAL;
 +		break;
 +	}
 +
 +	a->read_data_output_offset = 0;
 +	a->read_data_remaining = 0;
 +	/* EOF always wins; otherwise return the worst error. */
 +	return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1;
 +}
 +
 +int
 +_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
 +{
 +	int ret;
 +	struct archive_read *a = (struct archive_read *)_a;
 +	*entryp = NULL;
 +	ret = _archive_read_next_header2(_a, a->entry);
 +	*entryp = a->entry;
 +	return ret;
 +}
 +
 +/*
 + * Allow each registered format to bid on whether it wants to handle
 + * the next entry.  Return index of winning bidder.
 + */
 +static int
 +choose_format(struct archive_read *a)
 +{
 +	int slots;
 +	int i;
 +	int bid, best_bid;
 +	int best_bid_slot;
 +
 +	slots = sizeof(a->formats) / sizeof(a->formats[0]);
 +	best_bid = -1;
 +	best_bid_slot = -1;
 +
 +	/* Set up a->format for convenience of bidders. */
 +	a->format = &(a->formats[0]);
 +	for (i = 0; i < slots; i++, a->format++) {
 +		if (a->format->bid) {
 +			bid = (a->format->bid)(a, best_bid);
 +			if (bid == ARCHIVE_FATAL)
 +				return (ARCHIVE_FATAL);
 +			if (a->filter->position != 0)
 +				__archive_read_seek(a, 0, SEEK_SET);
 +			if ((bid > best_bid) || (best_bid_slot < 0)) {
 +				best_bid = bid;
 +				best_bid_slot = i;
 +			}
 +		}
 +	}
 +
 +	/*
 +	 * There were no bidders; this is a serious programmer error
 +	 * and demands a quick and definitive abort.
 +	 */
 +	if (best_bid_slot < 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "No formats registered");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * There were bidders, but no non-zero bids; this means we
 +	 * can't support this stream.
 +	 */
 +	if (best_bid < 1) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Unrecognized archive format");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	return (best_bid_slot);
 +}
 +
 +/*
 + * Return the file offset (within the uncompressed data stream) where
 + * the last header started.
 + */
 +int64_t
 +archive_read_header_position(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_ANY, "archive_read_header_position");
 +	return (a->header_position);
 +}
 +
 +/*
 + * Read data from an archive entry, using a read(2)-style interface.
 + * This is a convenience routine that just calls
 + * archive_read_data_block and copies the results into the client
 + * buffer, filling any gaps with zero bytes.  Clients using this
 + * API can be completely ignorant of sparse-file issues; sparse files
 + * will simply be padded with nulls.
 + *
 + * DO NOT intermingle calls to this function and archive_read_data_block
 + * to read a single entry body.
 + */
 +ssize_t
 +archive_read_data(struct archive *_a, void *buff, size_t s)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	char	*dest;
 +	const void *read_buf;
 +	size_t	 bytes_read;
 +	size_t	 len;
 +	int	 r;
 +
 +	bytes_read = 0;
 +	dest = (char *)buff;
 +
 +	while (s > 0) {
 +		if (a->read_data_remaining == 0) {
 +			read_buf = a->read_data_block;
 +			r = _archive_read_data_block(&a->archive, &read_buf,
 +			    &a->read_data_remaining, &a->read_data_offset);
 +			a->read_data_block = read_buf;
 +			if (r == ARCHIVE_EOF)
 +				return (bytes_read);
 +			/*
 +			 * Error codes are all negative, so the status
 +			 * return here cannot be confused with a valid
 +			 * byte count.  (ARCHIVE_OK is zero.)
 +			 */
 +			if (r < ARCHIVE_OK)
 +				return (r);
 +		}
 +
 +		if (a->read_data_offset < a->read_data_output_offset) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Encountered out-of-order sparse blocks");
 +			return (ARCHIVE_RETRY);
 +		}
 +
 +		/* Compute the amount of zero padding needed. */
 +		if (a->read_data_output_offset + s <
 +		    a->read_data_offset) {
 +			len = s;
 +		} else if (a->read_data_output_offset <
 +		    a->read_data_offset) {
 +			len = a->read_data_offset -
 +			    a->read_data_output_offset;
 +		} else
 +			len = 0;
 +
 +		/* Add zeroes. */
 +		memset(dest, 0, len);
 +		s -= len;
 +		a->read_data_output_offset += len;
 +		dest += len;
 +		bytes_read += len;
 +
 +		/* Copy data if there is any space left. */
 +		if (s > 0) {
 +			len = a->read_data_remaining;
 +			if (len > s)
 +				len = s;
 +			memcpy(dest, a->read_data_block, len);
 +			s -= len;
 +			a->read_data_block += len;
 +			a->read_data_remaining -= len;
 +			a->read_data_output_offset += len;
 +			a->read_data_offset += len;
 +			dest += len;
 +			bytes_read += len;
 +		}
 +	}
 +	return (bytes_read);
 +}
 +
- #if ARCHIVE_API_VERSION < 3
- /*
-  * Obsolete function provided for compatibility only.  Note that the API
-  * of this function doesn't allow the caller to detect if the remaining
-  * data from the archive entry is shorter than the buffer provided, or
-  * even if an error occurred while reading data.
-  */
- int
- archive_read_data_into_buffer(struct archive *a, void *d, ssize_t len)
- {
- 
- 	archive_read_data(a, d, len);
- 	return (ARCHIVE_OK);
- }
- #endif
- 
 +/*
 + * Skip over all remaining data in this entry.
 + */
 +int
 +archive_read_data_skip(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	int r;
 +	const void *buff;
 +	size_t size;
 +	int64_t offset;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
 +	    "archive_read_data_skip");
 +
 +	if (a->format->read_data_skip != NULL)
 +		r = (a->format->read_data_skip)(a);
 +	else {
 +		while ((r = archive_read_data_block(&a->archive,
 +			    &buff, &size, &offset))
 +		    == ARCHIVE_OK)
 +			;
 +	}
 +
 +	if (r == ARCHIVE_EOF)
 +		r = ARCHIVE_OK;
 +
 +	a->archive.state = ARCHIVE_STATE_HEADER;
 +	return (r);
 +}
 +
 +/*
 + * Read the next block of entry data from the archive.
 + * This is a zero-copy interface; the client receives a pointer,
 + * size, and file offset of the next available block of data.
 + *
 + * Returns ARCHIVE_OK if the operation is successful, ARCHIVE_EOF if
 + * the end of entry is encountered.
 + */
 +static int
 +_archive_read_data_block(struct archive *_a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
 +	    "archive_read_data_block");
 +
 +	if (a->format->read_data == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
 +		    "Internal error: "
 +		    "No format_read_data_block function registered");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	return (a->format->read_data)(a, buff, size, offset);
 +}
 +
 +static int
 +close_filters(struct archive_read *a)
 +{
 +	struct archive_read_filter *f = a->filter;
 +	int r = ARCHIVE_OK;
 +	/* Close each filter in the pipeline. */
 +	while (f != NULL) {
 +		struct archive_read_filter *t = f->upstream;
 +		if (!f->closed && f->close != NULL) {
 +			int r1 = (f->close)(f);
 +			f->closed = 1;
 +			if (r1 < r)
 +				r = r1;
 +		}
 +		free(f->buffer);
 +		f->buffer = NULL;
 +		f = t;
 +	}
 +	return r;
 +}
 +
 +static void
 +free_filters(struct archive_read *a)
 +{
 +	while (a->filter != NULL) {
 +		struct archive_read_filter *t = a->filter->upstream;
 +		free(a->filter);
 +		a->filter = t;
 +	}
 +}
 +
 +/*
 + * return the count of # of filters in use
 + */
 +static int
 +_archive_filter_count(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct archive_read_filter *p = a->filter;
 +	int count = 0;
 +	while(p) {
 +		count++;
 +		p = p->upstream;
 +	}
 +	return count;
 +}
 +
 +/*
 + * Close the file and all I/O.
 + */
 +static int
 +_archive_read_close(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	int r = ARCHIVE_OK, r1 = ARCHIVE_OK;
 +
 +	archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close");
 +	if (a->archive.state == ARCHIVE_STATE_CLOSED)
 +		return (ARCHIVE_OK);
 +	archive_clear_error(&a->archive);
 +	a->archive.state = ARCHIVE_STATE_CLOSED;
 +
 +	/* TODO: Clean up the formatters. */
 +
 +	/* Release the filter objects. */
 +	r1 = close_filters(a);
 +	if (r1 < r)
 +		r = r1;
 +
 +	return (r);
 +}
 +
 +/*
 + * Release memory and other resources.
 + */
 +static int
 +_archive_read_free(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	int i, n;
 +	int slots;
 +	int r = ARCHIVE_OK;
 +
 +	if (_a == NULL)
 +		return (ARCHIVE_OK);
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free");
 +	if (a->archive.state != ARCHIVE_STATE_CLOSED
 +	    && a->archive.state != ARCHIVE_STATE_FATAL)
 +		r = archive_read_close(&a->archive);
 +
 +	/* Call cleanup functions registered by optional components. */
 +	if (a->cleanup_archive_extract != NULL)
 +		r = (a->cleanup_archive_extract)(a);
 +
 +	/* Cleanup format-specific data. */
 +	slots = sizeof(a->formats) / sizeof(a->formats[0]);
 +	for (i = 0; i < slots; i++) {
 +		a->format = &(a->formats[i]);
 +		if (a->formats[i].cleanup)
 +			(a->formats[i].cleanup)(a);
 +	}
 +
 +	/* Free the filters */
 +	free_filters(a);
 +
 +	/* Release the bidder objects. */
 +	n = sizeof(a->bidders)/sizeof(a->bidders[0]);
 +	for (i = 0; i < n; i++) {
 +		if (a->bidders[i].free != NULL) {
 +			int r1 = (a->bidders[i].free)(&a->bidders[i]);
 +			if (r1 < r)
 +				r = r1;
 +		}
 +	}
 +
 +	archive_string_free(&a->archive.error_string);
 +	if (a->entry)
 +		archive_entry_free(a->entry);
 +	a->archive.magic = 0;
 +	__archive_clean(&a->archive);
 +	free(a);
 +	return (r);
 +}
 +
 +static struct archive_read_filter *
 +get_filter(struct archive *_a, int n)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct archive_read_filter *f = a->filter;
 +	/* We use n == -1 for 'the last filter', which is always the client proxy. */
 +	if (n == -1 && f != NULL) {
 +		struct archive_read_filter *last = f;
 +		f = f->upstream;
 +		while (f != NULL) {
 +			last = f;
 +			f = f->upstream;
 +		}
 +		return (last);
 +	}
 +	if (n < 0)
 +		return NULL;
 +	while (n > 0 && f != NULL) {
 +		f = f->upstream;
 +		--n;
 +	}
 +	return (f);
 +}
 +
 +static int
 +_archive_filter_code(struct archive *_a, int n)
 +{
 +	struct archive_read_filter *f = get_filter(_a, n);
 +	return f == NULL ? -1 : f->code;
 +}
 +
 +static const char *
 +_archive_filter_name(struct archive *_a, int n)
 +{
 +	struct archive_read_filter *f = get_filter(_a, n);
 +	return f != NULL ? f->name : NULL;
 +}
 +
 +static int64_t
 +_archive_filter_bytes(struct archive *_a, int n)
 +{
 +	struct archive_read_filter *f = get_filter(_a, n);
 +	return f == NULL ? -1 : f->position;
 +}
 +
 +/*
 + * Used internally by read format handlers to register their bid and
 + * initialization functions.
 + */
 +int
 +__archive_read_register_format(struct archive_read *a,
 +    void *format_data,
 +    const char *name,
 +    int (*bid)(struct archive_read *, int),
 +    int (*options)(struct archive_read *, const char *, const char *),
 +    int (*read_header)(struct archive_read *, struct archive_entry *),
 +    int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
 +    int (*read_data_skip)(struct archive_read *),
 +    int (*cleanup)(struct archive_read *))
 +{
 +	int i, number_slots;
 +
 +	archive_check_magic(&a->archive,
 +	    ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "__archive_read_register_format");
 +
 +	number_slots = sizeof(a->formats) / sizeof(a->formats[0]);
 +
 +	for (i = 0; i < number_slots; i++) {
 +		if (a->formats[i].bid == bid)
 +			return (ARCHIVE_WARN); /* We've already installed */
 +		if (a->formats[i].bid == NULL) {
 +			a->formats[i].bid = bid;
 +			a->formats[i].options = options;
 +			a->formats[i].read_header = read_header;
 +			a->formats[i].read_data = read_data;
 +			a->formats[i].read_data_skip = read_data_skip;
 +			a->formats[i].cleanup = cleanup;
 +			a->formats[i].data = format_data;
 +			a->formats[i].name = name;
 +			return (ARCHIVE_OK);
 +		}
 +	}
 +
 +	archive_set_error(&a->archive, ENOMEM,
 +	    "Not enough slots for format registration");
 +	return (ARCHIVE_FATAL);
 +}
 +
 +/*
 + * Used internally by decompression routines to register their bid and
 + * initialization functions.
 + */
 +int
 +__archive_read_get_bidder(struct archive_read *a,
 +    struct archive_read_filter_bidder **bidder)
 +{
 +	int i, number_slots;
 +
 +	number_slots = sizeof(a->bidders) / sizeof(a->bidders[0]);
 +
 +	for (i = 0; i < number_slots; i++) {
 +		if (a->bidders[i].bid == NULL) {
 +			memset(a->bidders + i, 0, sizeof(a->bidders[0]));
 +			*bidder = (a->bidders + i);
 +			return (ARCHIVE_OK);
 +		}
 +	}
 +
 +	archive_set_error(&a->archive, ENOMEM,
 +	    "Not enough slots for filter registration");
 +	return (ARCHIVE_FATAL);
 +}
 +
 +/*
 + * The next section implements the peek/consume internal I/O
 + * system used by archive readers.  This system allows simple
 + * read-ahead for consumers while preserving zero-copy operation
 + * most of the time.
 + *
 + * The two key operations:
 + *  * The read-ahead function returns a pointer to a block of data
 + *    that satisfies a minimum request.
 + *  * The consume function advances the file pointer.
 + *
 + * In the ideal case, filters generate blocks of data
 + * and __archive_read_ahead() just returns pointers directly into
 + * those blocks.  Then __archive_read_consume() just bumps those
 + * pointers.  Only if your request would span blocks does the I/O
 + * layer use a copy buffer to provide you with a contiguous block of
 + * data.
 + *
 + * A couple of useful idioms:
 + *  * "I just want some data."  Ask for 1 byte and pay attention to
 + *    the "number of bytes available" from __archive_read_ahead().
 + *    Consume whatever you actually use.
 + *  * "I want to output a large block of data."  As above, ask for 1 byte,
 + *    emit all that's available (up to whatever limit you have), consume
 + *    it all, then repeat until you're done.  This effectively means that
 + *    you're passing along the blocks that came from your provider.
 + *  * "I want to peek ahead by a large amount."  Ask for 4k or so, then
 + *    double and repeat until you get an error or have enough.  Note
 + *    that the I/O layer will likely end up expanding its copy buffer
 + *    to fit your request, so use this technique cautiously.  This
 + *    technique is used, for example, by some of the format tasting
 + *    code that has uncertain look-ahead needs.
 + */
 +
 +/*
 + * Looks ahead in the input stream:
 + *  * If 'avail' pointer is provided, that returns number of bytes available
 + *    in the current buffer, which may be much larger than requested.
 + *  * If end-of-file, *avail gets set to zero.
 + *  * If error, *avail gets error code.
 + *  * If request can be met, returns pointer to data.
 + *  * If minimum request cannot be met, returns NULL.
 + *
 + * Note: If you just want "some data", ask for 1 byte and pay attention
 + * to *avail, which will have the actual amount available.  If you
 + * know exactly how many bytes you need, just ask for that and treat
 + * a NULL return as an error.
 + *
 + * Important:  This does NOT move the file pointer.  See
 + * __archive_read_consume() below.
 + */
 +const void *
 +__archive_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
 +{
 +	return (__archive_read_filter_ahead(a->filter, min, avail));
 +}
 +
 +const void *
 +__archive_read_filter_ahead(struct archive_read_filter *filter,
 +    size_t min, ssize_t *avail)
 +{
 +	ssize_t bytes_read;
 +	size_t tocopy;
 +
 +	if (filter->fatal) {
 +		if (avail)
 +			*avail = ARCHIVE_FATAL;
 +		return (NULL);
 +	}
 +
 +	/*
 +	 * Keep pulling more data until we can satisfy the request.
 +	 */
 +	for (;;) {
 +
 +		/*
 +		 * If we can satisfy from the copy buffer (and the
 +		 * copy buffer isn't empty), we're done.  In particular,
 +		 * note that min == 0 is a perfectly well-defined
 +		 * request.
 +		 */
 +		if (filter->avail >= min && filter->avail > 0) {
 +			if (avail != NULL)
 +				*avail = filter->avail;
 +			return (filter->next);
 +		}
 +
 +		/*
 +		 * We can satisfy directly from client buffer if everything
 +		 * currently in the copy buffer is still in the client buffer.
 +		 */
 +		if (filter->client_total >= filter->client_avail + filter->avail
 +		    && filter->client_avail + filter->avail >= min) {
 +			/* "Roll back" to client buffer. */
 +			filter->client_avail += filter->avail;
 +			filter->client_next -= filter->avail;
 +			/* Copy buffer is now empty. */
 +			filter->avail = 0;
 +			filter->next = filter->buffer;
 +			/* Return data from client buffer. */
 +			if (avail != NULL)
 +				*avail = filter->client_avail;
 +			return (filter->client_next);
 +		}
 +
 +		/* Move data forward in copy buffer if necessary. */
 +		if (filter->next > filter->buffer &&
 +		    filter->next + min > filter->buffer + filter->buffer_size) {
 +			if (filter->avail > 0)
 +				memmove(filter->buffer, filter->next, filter->avail);
 +			filter->next = filter->buffer;
 +		}
 +
 +		/* If we've used up the client data, get more. */
 +		if (filter->client_avail <= 0) {
 +			if (filter->end_of_file) {
 +				if (avail != NULL)
 +					*avail = 0;
 +				return (NULL);
 +			}
 +			bytes_read = (filter->read)(filter,
 +			    &filter->client_buff);
 +			if (bytes_read < 0) {		/* Read error. */
 +				filter->client_total = filter->client_avail = 0;
 +				filter->client_next = filter->client_buff = NULL;
 +				filter->fatal = 1;
 +				if (avail != NULL)
 +					*avail = ARCHIVE_FATAL;
 +				return (NULL);
 +			}
 +			if (bytes_read == 0) {	/* Premature end-of-file. */
 +				filter->client_total = filter->client_avail = 0;
 +				filter->client_next = filter->client_buff = NULL;
 +				filter->end_of_file = 1;
 +				/* Return whatever we do have. */
 +				if (avail != NULL)
 +					*avail = filter->avail;
 +				return (NULL);
 +			}
 +			filter->client_total = bytes_read;
 +			filter->client_avail = filter->client_total;
 +			filter->client_next = filter->client_buff;
 +		}
 +		else
 +		{
 +			/*
 +			 * We can't satisfy the request from the copy
 +			 * buffer or the existing client data, so we
 +			 * need to copy more client data over to the
 +			 * copy buffer.
 +			 */
 +
 +			/* Ensure the buffer is big enough. */
 +			if (min > filter->buffer_size) {
 +				size_t s, t;
 +				char *p;
 +
 +				/* Double the buffer; watch for overflow. */
 +				s = t = filter->buffer_size;
 +				if (s == 0)
 +					s = min;
 +				while (s < min) {
 +					t *= 2;
 +					if (t <= s) { /* Integer overflow! */
 +						archive_set_error(
 +							&filter->archive->archive,
 +							ENOMEM,
 +						    "Unable to allocate copy buffer");
 +						filter->fatal = 1;
 +						if (avail != NULL)
 +							*avail = ARCHIVE_FATAL;
 +						return (NULL);
 +					}
 +					s = t;
 +				}
 +				/* Now s >= min, so allocate a new buffer. */
 +				p = (char *)malloc(s);
 +				if (p == NULL) {
 +					archive_set_error(
 +						&filter->archive->archive,
 +						ENOMEM,
 +					    "Unable to allocate copy buffer");
 +					filter->fatal = 1;
 +					if (avail != NULL)
 +						*avail = ARCHIVE_FATAL;
 +					return (NULL);
 +				}
 +				/* Move data into newly-enlarged buffer. */
 +				if (filter->avail > 0)
 +					memmove(p, filter->next, filter->avail);
 +				free(filter->buffer);
 +				filter->next = filter->buffer = p;
 +				filter->buffer_size = s;
 +			}
 +
 +			/* We can add client data to copy buffer. */
 +			/* First estimate: copy to fill rest of buffer. */
 +			tocopy = (filter->buffer + filter->buffer_size)
 +			    - (filter->next + filter->avail);
 +			/* Don't waste time buffering more than we need to. */
 +			if (tocopy + filter->avail > min)
 +				tocopy = min - filter->avail;
 +			/* Don't copy more than is available. */
 +			if (tocopy > filter->client_avail)
 +				tocopy = filter->client_avail;
 +
 +			memcpy(filter->next + filter->avail, filter->client_next,
 +			    tocopy);
 +			/* Remove this data from client buffer. */
 +			filter->client_next += tocopy;
 +			filter->client_avail -= tocopy;
 +			/* add it to copy buffer. */
 +			filter->avail += tocopy;
 +		}
 +	}
 +}
 +
 +/*
 + * Move the file pointer forward.
 + */
 +int64_t
 +__archive_read_consume(struct archive_read *a, int64_t request)
 +{
 +	return (__archive_read_filter_consume(a->filter, request));
 +}
 +
 +int64_t
 +__archive_read_filter_consume(struct archive_read_filter * filter,
 +    int64_t request)
 +{
 +	int64_t skipped;
 +
 +	if (request == 0)
 +		return 0;
 +
 +	skipped = advance_file_pointer(filter, request);
 +	if (skipped == request)
 +		return (skipped);
 +	/* We hit EOF before we satisfied the skip request. */
 +	if (skipped < 0)  /* Map error code to 0 for error message below. */
 +		skipped = 0;
 +	archive_set_error(&filter->archive->archive,
 +	    ARCHIVE_ERRNO_MISC,
 +	    "Truncated input file (needed %jd bytes, only %jd available)",
 +	    (intmax_t)request, (intmax_t)skipped);
 +	return (ARCHIVE_FATAL);
 +}
 +
 +/*
 + * Advance the file pointer by the amount requested.
 + * Returns the amount actually advanced, which may be less than the
 + * request if EOF is encountered first.
 + * Returns a negative value if there's an I/O error.
 + */
 +static int64_t
 +advance_file_pointer(struct archive_read_filter *filter, int64_t request)
 +{
 +	int64_t bytes_skipped, total_bytes_skipped = 0;
 +	ssize_t bytes_read;
 +	size_t min;
 +
 +	if (filter->fatal)
 +		return (-1);
 +
 +	/* Use up the copy buffer first. */
 +	if (filter->avail > 0) {
 +		min = minimum(request, (int64_t)filter->avail);
 +		filter->next += min;
 +		filter->avail -= min;
 +		request -= min;
 +		filter->position += min;
 +		total_bytes_skipped += min;
 +	}
 +
 +	/* Then use up the client buffer. */
 +	if (filter->client_avail > 0) {
 +		min = minimum(request, (int64_t)filter->client_avail);
 +		filter->client_next += min;
 +		filter->client_avail -= min;
 +		request -= min;
 +		filter->position += min;
 +		total_bytes_skipped += min;
 +	}
 +	if (request == 0)
 +		return (total_bytes_skipped);
 +
 +	/* If there's an optimized skip function, use it. */
 +	if (filter->skip != NULL) {
 +		bytes_skipped = (filter->skip)(filter, request);
 +		if (bytes_skipped < 0) {	/* error */
 +			filter->fatal = 1;
 +			return (bytes_skipped);
 +		}
 +		filter->position += bytes_skipped;
 +		total_bytes_skipped += bytes_skipped;
 +		request -= bytes_skipped;
 +		if (request == 0)
 +			return (total_bytes_skipped);
 +	}
 +
 +	/* Use ordinary reads as necessary to complete the request. */
 +	for (;;) {
 +		bytes_read = (filter->read)(filter, &filter->client_buff);
 +		if (bytes_read < 0) {
 +			filter->client_buff = NULL;
 +			filter->fatal = 1;
 +			return (bytes_read);
 +		}
 +
 +		if (bytes_read == 0) {
 +			filter->client_buff = NULL;
 +			filter->end_of_file = 1;
 +			return (total_bytes_skipped);
 +		}
 +
 +		if (bytes_read >= request) {
 +			filter->client_next =
 +			    ((const char *)filter->client_buff) + request;
 +			filter->client_avail = bytes_read - request;
 +			filter->client_total = bytes_read;
 +			total_bytes_skipped += request;
 +			filter->position += request;
 +			return (total_bytes_skipped);
 +		}
 +
 +		filter->position += bytes_read;
 +		total_bytes_skipped += bytes_read;
 +		request -= bytes_read;
 +	}
 +}
 +
 +/**
 + * Returns ARCHIVE_FAILED if seeking isn't supported.
 + */
 +int64_t
 +__archive_read_seek(struct archive_read *a, int64_t offset, int whence)
 +{
 +	return __archive_read_filter_seek(a->filter, offset, whence);
 +}
 +
 +int64_t
 +__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset, int whence)
 +{
 +	int64_t r;
 +
 +	if (filter->closed || filter->fatal)
 +		return (ARCHIVE_FATAL);
 +	if (filter->seek == NULL)
 +		return (ARCHIVE_FAILED);
 +	r = filter->seek(filter, offset, whence);
 +	if (r >= 0) {
 +		/*
 +		 * Ouch.  Clearing the buffer like this hurts, especially
 +		 * at bid time.  A lot of our efficiency at bid time comes
 +		 * from having bidders reuse the data we've already read.
 +		 *
 +		 * TODO: If the seek request is in data we already
 +		 * have, then don't call the seek callback.
 +		 *
 +		 * TODO: Zip seeks to end-of-file at bid time.  If
 +		 * other formats also start doing this, we may need to
 +		 * find a way for clients to fudge the seek offset to
 +		 * a block boundary.
 +		 *
 +		 * Hmmm... If whence was SEEK_END, we know the file
 +		 * size is (r - offset).  Can we use that to simplify
 +		 * the TODO items above?
 +		 */
 +		filter->avail = filter->client_avail = 0;
 +		filter->next = filter->buffer;
 +		filter->position = r;
 +		filter->end_of_file = 0;
 +	}
 +	return r;
 +}
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
index 3a12405,0000000..1580c92
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
@@@ -1,3687 -1,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 <cm_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 convertion 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 ssize_t	decode_header_image(struct archive_read *, struct _7zip *,
- 		    struct _7z_stream_info *, const unsigned char *, uint64_t,
- 		    const void **);
++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 *);
++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, 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(const unsigned char *, size_t, uint64_t *);
- static int	read_Bools(unsigned char *, size_t, const unsigned char *,
- 		    size_t);
- static int	read_CodersInfo(struct _7z_coders_info *,
- 		    const unsigned char *, size_t);
- static int	read_Digests(struct _7z_digests *, size_t,
- 		    const unsigned char *, size_t);
- static int	read_Folder(struct _7z_folder *, const unsigned char *,
- 		    size_t);
- static int	read_Header(struct _7zip *, struct _7z_header_info *,
- 		    const unsigned char *, size_t);
- static int	read_PackInfo(struct _7z_pack_info *, const unsigned char *,
++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_StreamsInfo(struct _7zip *, struct _7z_stream_info *,
- 		    const unsigned char *, size_t);
- static int	read_SubStreamsInfo(struct _7z_substream_info *,
- 		    struct _7z_folder *, size_t, const unsigned char *,
- 		    size_t);
- static int	read_Times(struct _7zip *, struct _7z_header_info *, int,
- 		    const unsigned char *, 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);
++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 size_t	x86_Convert(uint8_t *, size_t, uint32_t, uint32_t *);
- ssize_t		Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
++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, (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 != -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;
 +		int r;
 +
 +		/*
- 		 * Symbolic-name is recorded as its contents. We have to read the
- 		 * contents at this time.
++		 * 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);
++			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. */
++			/* 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);
++			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);
++	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. */
- 					zip->bcj_state = 0;
++					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 > 0) {
++		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)
++				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_in < 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(buff, *outbytes, 0, &(zip->bcj_state));
++		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(const unsigned char *p, size_t len, uint64_t *val)
++parse_7zip_uint64(struct archive_read *a, uint64_t *val)
 +{
- 	const unsigned char *_p = p;
++	const unsigned char *p;
 +	unsigned char avail, mask;
 +	int i;
 +
- 	if (len-- == 0)
++	if ((p = header_bytes(a, 1)) == NULL)
 +		return (-1);
- 	avail = *p++;
++	avail = *p;
 +	mask = 0x80;
 +	*val = 0;
 +	for (i = 0; i < 8; i++) {
 +		if (avail & mask) {
- 			if (len-- == 0)
++			if ((p = header_bytes(a, 1)) == NULL)
 +				return (-1);
- 			*val |= ((uint64_t)*p++) << (8 * i);
++			*val |= ((uint64_t)*p) << (8 * i);
 +			mask >>= 1;
 +			continue;
 +		}
 +		*val += (avail & (mask -1)) << (8 * i);
 +		break;
 +	}
- 	return (p - _p);
++	return (0);
 +}
 +
 +static int
- read_Bools(unsigned char *data, size_t num, const unsigned char *p, size_t len)
++read_Bools(struct archive_read *a, unsigned char *data, size_t num)
 +{
- 	const unsigned char *_p = p;
- 	unsigned i, mask = 0, avail;
++	const unsigned char *p;
++	unsigned i, mask = 0, avail = 0;
 +
 +	for (i = 0; i < num; i++) {
 +		if (mask == 0) {
- 			if (len == 0)
++			if ((p = header_bytes(a, 1)) == NULL)
 +				return (-1);
- 			avail = *p++;
- 			len--;
++			avail = *p;
 +			mask = 0x80;
 +		}
 +		data[i] = (avail & mask)?1:0;
 +		mask >>= 1;
 +	}
- 	return (p - _p);
++	return (0);
 +}
 +
 +static void
 +free_Digest(struct _7z_digests *d)
 +{
 +	free(d->defineds);
 +	free(d->digests);
 +}
 +
 +static int
- read_Digests(struct _7z_digests *d, size_t num, const unsigned char *p,
-     size_t len)
++read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num)
 +{
- 	const unsigned char *_p = p;
++	const unsigned char *p;
 +	unsigned i;
 +
 +	memset(d, 0, sizeof(*d));
 +
- 	if (len == 0)
- 		return (-1);
 +
 +	d->defineds = malloc(num);
 +	if (d->defineds == NULL)
 +		return (-1);
 +	/*
 +	 * Read Bools.
 +	 */
- 	len--;
- 	if (*p++ == 0) {
- 		int r = read_Bools(d->defineds, num, p, len);
- 		if (r < 0)
++	if ((p = header_bytes(a, 1)) == NULL)
++		return (-1);
++	if (*p == 0) {
++		if (read_Bools(a, d->defineds, num) < 0)
 +			return (-1);
- 		p += r;
- 		len -= r;
 +	} else
 +		/* All are defined */
 +		memset(d->defineds, 1, num);
 +
 +	d->digests = calloc(num, sizeof(*d->digests));
 +	if (d->digests == NULL)
 +		return (-1);
- 	if (len < 4 * num)
- 		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);
- 			p += 4;
- 			len -= 4;
 +		}
 +	}
 +
- 	return (p - _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 _7z_pack_info *pi, const unsigned char *p, size_t len)
++read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
 +{
- 	const unsigned char *_p = p;
++	const unsigned char *p;
 +	unsigned i;
- 	int r;
 +
 +	memset(pi, 0, sizeof(*pi));
 +
- 	if (len < 3 || *p++ != kPackInfo)
- 		return (-1);
- 	--len;
- 
 +	/*
 +	 * Read PackPos.
 +	 */
- 	r = parse_7zip_uint64(p, len, &(pi->pos));
- 	if (r < 0)
- 		return (r);
- 	p += r;
- 	len -= r;
++	if (parse_7zip_uint64(a, &(pi->pos)) < 0)
++		return (-1);
 +
 +	/*
 +	 * Read NumPackStreams.
 +	 */
- 	r = parse_7zip_uint64(p, len, &(pi->numPackStreams));
- 	if (r < 0 || pi->numPackStreams == 0)
- 		return (r);
- 	p += r;
- 	len -= r;
++	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 (len >= 1 && *p == kEnd)
++	if ((p = header_bytes(a, 1)) == NULL)
++		return (-1);
++	if (*p == kEnd)
 +		/* PackSizes[num] are not present. */
- 		return (p - _p + 1);
- 	if (len < 1 + pi->numPackStreams || *p++ != kSize)
++		return (0);
++	if (*p != kSize)
 +		return (-1);
- 	--len;
 +	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++) {
- 		r = parse_7zip_uint64(p, len, &(pi->sizes[i]));
- 		if (r < 0)
++		if (parse_7zip_uint64(a, &(pi->sizes[i])) < 0)
 +			return (-1);
- 		p += r;
- 		len -= r;
 +	}
 +
 +	/*
 +	 * Read PackStreamDigests[num]
 +	 */
- 	if (len >= 1 && *p == kEnd) {
++	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 (p - _p + 1);
++		return (0);
 +	}
 +
- 	if (len < 1 + pi->numPackStreams || *p++ != kSize)
++	if (*p != kSize)
 +		return (-1);
- 	--len;
 +
- 	r = read_Digests(&(pi->digest), pi->numPackStreams, p, len);
- 	if (r < 0)
++	if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0)
 +		return (-1);
- 	p += r;
- 	len -= r;
 +
 +	/*
 +	 *  Must be marked by kEnd.
 +	 */
- 	if (len == 0 || *p++ != kEnd)
++	if ((p = header_bytes(a, 1)) == NULL)
++		return (-1);
++	if (*p != kEnd)
 +		return (-1);
- 	return (p - _p);
++	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 _7z_folder *f, const unsigned char *p, size_t len)
++read_Folder(struct archive_read *a, struct _7z_folder *f)
 +{
- 	const unsigned char *_p = p;
++	struct _7zip *zip = (struct _7zip *)a->format->data;
++	const unsigned char *p;
 +	uint64_t numInStreamsTotal = 0;
 +	uint64_t numOutStreamsTotal = 0;
- 	int r;
 +	unsigned i;
 +
 +	memset(f, 0, sizeof(*f));
 +
 +	/*
 +	 * Read NumCoders.
 +	 */
- 	r = parse_7zip_uint64(p, len, &(f->numCoders));
- 	if (r < 0)
++	if (parse_7zip_uint64(a, &(f->numCoders)) < 0)
++		return (-1);
++	if (f->numCoders > 4)
++		/* Too many coders. */
 +		return (-1);
- 	p += r;
- 	len -= r;
 +
 +	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 (len == 0)
++		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. */
- 		p++;
- 		len--;
 +
 +		/*
 +		 * Read Decompression Method IDs.
 +		 */
- 		if (len < codec_size)
++		if ((p = header_bytes(a, codec_size)) == NULL)
 +			return (-1);
 +
 +		f->coders[i].codec = decode_codec_id(p, codec_size);
- 		p += codec_size;
- 		len -= codec_size;
 +
 +		if (simple) {
 +			f->coders[i].numInStreams = 1;
 +			f->coders[i].numOutStreams = 1;
 +		} else {
- 			r = parse_7zip_uint64(p, len,
- 			    &(f->coders[i].numInStreams));
- 			if (r < 0)
++			if (parse_7zip_uint64(
++			    a, &(f->coders[i].numInStreams)) < 0)
 +				return (-1);
- 			p += r;
- 			len -= r;
- 			r = parse_7zip_uint64(p, len,
- 			    &(f->coders[i].numOutStreams));
- 			if (r < 0)
++			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);
- 			p += r;
- 			len -= r;
 +		}
 +
 +		if (attr) {
- 			r = parse_7zip_uint64(p, len,
- 				&(f->coders[i].propertiesSize));
- 			if (r < 0)
++			if (parse_7zip_uint64(
++			    a, &(f->coders[i].propertiesSize)) < 0)
 +				return (-1);
- 			p += r;
- 			len -= r;
- 
- 			if (len < f->coders[i].propertiesSize)
++			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);
- 			p += f->coders[i].propertiesSize;
- 			len -= 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++) {
- 		r = parse_7zip_uint64(p, len, &(f->bindPairs[i].inIndex));
- 		if (r < 0)
++		if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
 +			return (-1);
- 		p += r;
- 		len -= r;
- 		r = parse_7zip_uint64(p, len, &(f->bindPairs[i].outIndex));
- 		if (r < 0)
++		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);
- 		p += r;
- 		len -= r;
 +	}
 +
 +	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++) {
- 			r = parse_7zip_uint64(p, len, &(f->packedStreams[i]));
- 			if (r < 0)
++			if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)
++				return (-1);
++			if (1000000 < f->packedStreams[i])
 +				return (-1);
- 			p += r;
- 			len -= r;
 +		}
 +	}
 +	f->numInStreams = numInStreamsTotal;
 +	f->numOutStreams = numOutStreamsTotal;
 +
- 	return (p - _p);
++	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 _7z_coders_info *ci, const unsigned char *p, size_t len)
++read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
 +{
- 	const unsigned char *_p = p;
++	const unsigned char *p;
 +	struct _7z_digests digest;
- 	unsigned i, external;
- 	int r;
++	unsigned i;
 +
 +	memset(ci, 0, sizeof(*ci));
 +	memset(&digest, 0, sizeof(digest));
 +
- 	if (len < 3 || *p++ != kUnPackInfo)
++	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
- 	--len;
- 
- 	if (len < 3 || *p++ != kFolder)
++	if (*p != kFolder)
 +		goto failed;
- 	--len;
 +
 +	/*
 +	 * Read NumFolders.
 +	 */
- 	r = parse_7zip_uint64(p, len, &(ci->numFolders));
- 	if (r < 0)
++	if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
 +		goto failed;
- 	p += r;
- 	len -= r;
++	if (1000000 < ci->numFolders)
++			return (-1);
 +
 +	/*
 +	 * Read External.
 +	 */
- 	if (len == 0)
++	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
- 	external = *p++;
- 	len --;
- 	switch (external) {
++	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++) {
- 			r = read_Folder(&(ci->folders[i]), p, len);
- 			if (r < 0)
++			if (read_Folder(a, &(ci->folders[i])) < 0)
 +				goto failed;
- 			p += r;
- 			len -= r;
 +		}
 +		break;
 +	case 1:
- 		r = parse_7zip_uint64(p, len, &(ci->dataStreamIndex));
- 		if (r < 0)
- 			return (r);
- 		p += r;
- 		len -= r;
++		if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
++			return (-1);
++		if (1000000 < ci->dataStreamIndex)
++			return (-1);
 +		break;
 +	}
 +
- 	if (len < 1 + ci->numFolders || *p++ != kCodersUnPackSize)
++	if ((p = header_bytes(a, 1)) == NULL)
++		goto failed;
++	if (*p != kCodersUnPackSize)
 +		goto failed;
- 	--len;
 +
 +	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++) {
- 			r = parse_7zip_uint64(p, len,
- 			      &(folder->unPackSize[j]));
- 			if (r < 0)
++			if (parse_7zip_uint64(a, &(folder->unPackSize[j])) < 0)
 +				goto failed;
- 			p += r;
- 			len -= r;
 +		}
 +	}
 +
 +	/*
 +	 * Read CRCs.
 +	 */
- 	if (len == 0)
++	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
 +	if (*p == kEnd)
- 		return (p - _p + 1);
- 	if (len < 1 + ci->numFolders || *p++ != kCRC)
++		return (0);
++	if (*p != kCRC)
 +		goto failed;
- 	--len;
- 	r = read_Digests(&digest, ci->numFolders, p, len);
- 	if (r < 0)
++	if (read_Digests(a, &digest, ci->numFolders) < 0)
 +		goto failed;
- 	p += r;
- 	len -= r;
 +	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 (len == 0 || *p++ != kEnd)
++	if ((p = header_bytes(a, 1)) == NULL)
++		goto failed;
++	if (*p != kEnd)
 +		goto failed;
 +	free_Digest(&digest);
- 	return (p - _p);
++	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 == 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 _7z_substream_info *ss, struct _7z_folder *f,
-     size_t numFolders, const unsigned char *p, size_t len)
++read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
++    struct _7z_folder *f, size_t numFolders)
 +{
- 	const unsigned char *_p = p;
++	const unsigned char *p;
 +	uint64_t *usizes;
 +	size_t unpack_streams;
- 	int r, type;
++	int type;
 +	unsigned i;
 +	uint32_t numDigests;
 +
 +	memset(ss, 0, sizeof(*ss));
 +
- 	if (len < 2 || *p++ != kSubStreamsInfo)
- 		return (-1);
- 	--len;
- 
 +	for (i = 0; i < numFolders; i++)
 +		f[i].numUnpackStreams = 1;
 +
- 	if (len < 1)
++	if ((p = header_bytes(a, 1)) == NULL)
 +		return (-1);
- 	type = *p++;
- 	--len;
++	type = *p;
 +
 +	if (type == kNumUnPackStream) {
 +		unpack_streams = 0;
 +		for (i = 0; i < numFolders; i++) {
- 			r = parse_7zip_uint64(p, len, &(f[i].numUnpackStreams));
- 			if (r < 0)
++			if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)
++				return (-1);
++			if (1000000 < f[i].numUnpackStreams)
 +				return (-1);
- 			p += r;
- 			len -= r;
 +			unpack_streams += f[i].numUnpackStreams;
 +		}
- 		if (len < 1)
++		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
- 		type = *p++;
- 		--len;
++		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++) {
- 				r = parse_7zip_uint64(p, len, usizes);
- 				if (r < 0)
++				if (parse_7zip_uint64(a, usizes) < 0)
 +					return (-1);
- 				p += r;
- 				len -= r;
 +				sum += *usizes++;
 +			}
 +		}
 +		*usizes++ = folder_uncompressed_size(&f[i]) - sum;
 +	}
 +
 +	if (type == kSize) {
- 		if (len < 1)
++		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
- 		type = *p++;
- 		--len;
++		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)
++		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));
- 		r = read_Digests(&(tmpDigests), numDigests, p, len);
- 		if (r < 0) {
++		if (read_Digests(a, &(tmpDigests), numDigests) < 0) {
 +			free_Digest(&tmpDigests);
 +			return (-1);
 +		}
- 		p += r;
- 		len -= r;
 +		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 (len < 1)
++		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
- 		type = *p++;
- 		--len;
++		type = *p;
 +	}
 +
 +	/*
 +	 *  Must be kEnd.
 +	 */
 +	if (type != kEnd)
 +		return (-1);
- 	return (p - _p);
++	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 _7zip *zip, struct _7z_stream_info *si,
-     const unsigned char *p, size_t len)
++read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
 +{
- 	const unsigned char *_p = p;
++	struct _7zip *zip = (struct _7zip *)a->format->data;
++	const unsigned char *p;
 +	unsigned i;
- 	int r;
 +
 +	memset(si, 0, sizeof(*si));
 +
- 	if (len > 0 && *p == kPackInfo) {
++	if ((p = header_bytes(a, 1)) == NULL)
++		return (-1);
++	if (*p == kPackInfo) {
 +		uint64_t packPos;
 +
- 		r = read_PackInfo(&(si->pi), p, len);
- 		if (r < 0)
++		if (read_PackInfo(a, &(si->pi)) < 0)
 +			return (-1);
- 		p += r;
- 		len -= r;
 +
++		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 (len > 0 && *p == kUnPackInfo) {
++	if (*p == kUnPackInfo) {
 +		uint32_t packIndex;
 +		struct _7z_folder *f;
 +
- 		r = read_CodersInfo(&(si->ci), p, len);
- 		if (r < 0)
++		if (read_CodersInfo(a, &(si->ci)) < 0)
 +			return (-1);
- 		p += r;
- 		len -= r;
 +
 +		/*
 +		 * 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 (len > 0 && *p == kSubStreamsInfo) {
- 		r = read_SubStreamsInfo(&(si->ss),
- 		    si->ci.folders, si->ci.numFolders, p, len);
- 		if (r < 0)
++
++	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);
- 		p += r;
- 		len -= r;
 +	}
 +
 +	/*
 +	 *  Must be kEnd.
 +	 */
- 	if (len == 0 || *p++ != kEnd)
++	if (*p != kEnd)
 +		return (-1);
- 	return (p - _p);
++	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 _7zip *zip, struct _7z_header_info *h,
-     const unsigned char *p, size_t len)
++read_Header(struct archive_read *a, struct _7z_header_info *h,
++    int check_header_id)
 +{
- 	const unsigned char *_p = p;
++	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, r, sindex;
++	int eindex, empty_streams, sindex;
 +
- 	if (len < 2 || *p++ != kHeader)
- 		return (-1);
- 	len--;
++	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) {
- 		p++;
- 		len--;
- 
 +		for (;;) {
 +			uint64_t size;
- 			int atype = *p++;
- 			len--;
- 			if (atype == 0)
++			if ((p = header_bytes(a, 1)) == NULL)
++				return (-1);
++			if (*p == 0)
 +				break;
- 			r = parse_7zip_uint64(p, len, &size);
- 			if (r < 0 || len < r + size)
++			if (parse_7zip_uint64(a, &size) < 0)
 +				return (-1);
- 			p += r + size;
- 			len -= r + size;
 +		}
++		if ((p = header_bytes(a, 1)) == NULL)
++			return (-1);
 +	}
 +
 +	/*
 +	 * Read MainStreamsInfo.
 +	 */
 +	if (*p == kMainStreamsInfo) {
- 		p++;
- 		len--;
- 		r = read_StreamsInfo(zip, &(zip->si), p, len);
- 		if (r < 0)
++		if (read_StreamsInfo(a, &(zip->si)) < 0)
++			return (-1);
++		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
- 		p += r;
- 		len -= r;
 +	}
- 	if (len == 0)
- 		return (-1);
 +	if (*p == kEnd)
- 		return (p - _p + 1);
++		return (0);
 +
 +	/*
 +	 * Read FilesInfo.
 +	 */
- 	if (len < 2 || *p++ != kFilesInfo)
++	if (*p != kFilesInfo)
 +		return (-1);
- 	len--;
 +
- 	r = parse_7zip_uint64(p, len, &(zip->numFiles));
- 	if (r < 0)
++	if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
 +		return (-1);
- 	p += r;
- 	len -= r;
++	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 (len < 1)
++		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
- 		type = *p++;
- 		len--;
++		type = *p;
 +		if (type == kEnd)
 +			break;
 +
- 		r = parse_7zip_uint64(p, len, &size);
- 		if (r < 0 || len < size)
++		if (parse_7zip_uint64(a, &size) < 0)
++			return (-1);
++		if (zip->header_bytes_remaining < size)
 +			return (-1);
- 		p += r;
- 		len -= r;
 +		ll = (size_t)size;
- 		len -= ll;
 +
 +		switch (type) {
 +		case kEmptyStream:
 +			h->emptyStreamBools = calloc(zip->numFiles,
 +			    sizeof(*h->emptyStreamBools));
 +			if (h->emptyStreamBools == NULL)
 +				return (-1);
- 			r = read_Bools(h->emptyStreamBools, zip->numFiles,
- 			    p, ll);
- 			if (r < 0)
++			if (read_Bools(
++			    a, h->emptyStreamBools, zip->numFiles) < 0)
 +				return (-1);
- 			p += r;
- 			ll -= r;
 +			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);
- 			r = read_Bools(h->emptyFileBools, empty_streams,
- 			    p, len);
- 			if (r < 0)
++			if (read_Bools(a, h->emptyFileBools, empty_streams) < 0)
 +				return (-1);
- 			p += r;
- 			ll -= r;
 +			break;
 +		case kAnti:
 +			h->antiBools = calloc(empty_streams,
 +			    sizeof(*h->antiBools));
 +			if (h->antiBools == NULL)
 +				return (-1);
- 			r = read_Bools(h->antiBools, empty_streams, p, len);
- 			if (r < 0)
++			if (read_Bools(a, h->antiBools, empty_streams) < 0)
 +				return (-1);
- 			p += r;
- 			ll -= r;
 +			break;
 +		case kCTime:
 +		case kATime:
 +		case kMTime:
- 			r = read_Times(zip, h, type, p, ll);
- 			if (r < 0)
++			if (read_Times(a, h, type) < 0)
 +				return (-1);
- 			p += r;
- 			ll -= r;
 +			break;
 +		case kName:
 +		{
 +			unsigned char *np;
- 			size_t nl;
++			size_t nl, nb;
 +
- 			if (ll < 1)
++			/* Skip one byte. */
++			if ((p = header_bytes(a, 1)) == NULL)
 +				return (-1);
- 			p++; ll--;/* Skip one byte. */
++			ll--;
++
 +			if ((ll & 1) || ll < zip->numFiles * 4)
 +				return (-1);
 +
 +			zip->entry_names = malloc(ll);
 +			if (zip->entry_names == NULL)
 +				return (-1);
- 			memcpy(zip->entry_names, p, ll);
++			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 (ll < 2)
++			if ((p = header_bytes(a, 2)) == NULL)
 +				return (-1);
- 			allAreDefined = *p++;
- 			--ll;
- 			p++; --ll;/* Skip one byte. */
++			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 {
- 				r = read_Bools(h->attrBools,
- 				      zip->numFiles, p, ll);
- 				if (r < 0)
++				if (read_Bools(a, h->attrBools,
++				      zip->numFiles) < 0)
 +					return (-1);
- 				p += r;
- 				ll -= r;
 +			}
 +			for (i = 0; i < zip->numFiles; i++) {
 +				if (h->attrBools[i]) {
- 					if (ll < 4)
++					if ((p = header_bytes(a, 4)) == NULL)
 +						return (-1);
 +					entries[i].attr = archive_le32dec(p);
- 					p += 4;
- 					ll -= 4;
 +				}
 +			}
 +			break;
 +		}
 +		default:
++			if (header_bytes(a, ll) == NULL)
++				return (-1);
 +			break;
 +		}
- 		/* Skip remaining data. */
- 		p += ll;
 +	}
 +
 +	/*
 +	 * 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)
++		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 (p - _p);
++	return (0);
 +}
 +
 +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 +static void
 +fileTimeToUtc(uint64_t fileTime, time_t *time, long *ns)
 +{
 +
 +	if (fileTime >= EPOC_TIME) {
 +		fileTime -= EPOC_TIME;
 +		/* milli seconds base */
 +		*time = (time_t)(fileTime / 10000000);
 +		/* nano seconds base */
 +		*ns = (long)(fileTime % 10000000) * 100;
 +	} else {
 +		*time = 0;
 +		*ns = 0;
 +	}
 +}
 +
 +static int
- read_Times(struct _7zip *zip, struct _7z_header_info *h, int type,
-     const unsigned char *p, size_t len)
++read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
 +{
- 	const unsigned char *_p = p;
++	struct _7zip *zip = (struct _7zip *)a->format->data;
++	const unsigned char *p;
 +	struct _7zip_entry *entries = zip->entries;
 +	unsigned char *timeBools;
- 	int r;
- 	int allAreDefined, external;
++	int allAreDefined;
 +	unsigned i;
 +
 +	timeBools = calloc(zip->numFiles, sizeof(*timeBools));
 +	if (timeBools == NULL)
 +		return (-1);
 +
- 	if (len < 1)
++	/* Read allAreDefined. */
++	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
- 	allAreDefined = *p++;
- 	len--;
++	allAreDefined = *p;
 +	if (allAreDefined)
 +		memset(timeBools, 1, zip->numFiles);
 +	else {
- 		r = read_Bools(timeBools, zip->numFiles, p, len);
- 		if (r < 0)
++		if (read_Bools(a, timeBools, zip->numFiles) < 0)
 +			goto failed;
- 		p += r;
- 		len -= r;
 +	}
 +
- 	if (len < 1)
++	/* Read external. */
++	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
- 	external = *p++;
- 	len--;
- 	if (external) {
- 		r = parse_7zip_uint64(p, len, &(h->dataIndex));
- 		if (r < 0)
++	if (*p) {
++		if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
 +			goto failed;
- 		p += r;
- 		len -= r;
++		if (1000000 < h->dataIndex)
++			return (-1);
 +	}
 +
 +	for (i = 0; i < zip->numFiles; i++) {
 +		if (!timeBools[i])
 +			continue;
- 		if (len < 8)
++		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;
 +		}
- 		p += 8;
- 		len -= 8;
 +	}
 +
 +	free(timeBools);
- 	return (p - _p);
++	return (0);
 +failed:
 +	free(timeBools);
 +	return (-1);
 +}
 +
- static ssize_t
- decode_header_image(struct archive_read *a, struct _7zip *zip,
-     struct _7z_stream_info *si, const unsigned char *p, uint64_t len,
-     const void **image)
++static int
++decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)
 +{
- 	const unsigned char *v;
- 	size_t vsize;
- 	int r;
++	struct _7zip *zip = (struct _7zip *)a->format->data;
 +
 +	errno = 0;
- 	r = read_StreamsInfo(zip, si, p, len);
- 	if (r < 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);
 +	}
 +
- 	r = setup_decode_folder(a, si->ci.folders, 1);
- 	if (r != ARCHIVE_OK)
- 		return (ARCHIVE_FATAL);
- 
- 	/* Get an uncompressed header size. */
- 	vsize = (size_t)zip->folder_outbytes_remaining;
- 
- 	/*
- 	 * Allocate an uncompressed buffer for the header image.
- 	 */
- 	zip->uncompressed_buffer_size = 64 * 1024;
- 	if (vsize > zip->uncompressed_buffer_size)
- 		zip->uncompressed_buffer_size = vsize;
- 	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);
- 	}
++	return (ARCHIVE_OK);
++}
 +
- 	/* Get the bytes we can read to decode the header. */
- 	zip->pack_stream_inbytes_remaining = si->pi.sizes[0];
++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;
 +
- 	/* Seek the read point. */
- 	if (__archive_read_seek(a, si->pi.pos + zip->seek_base, SEEK_SET) < 0)
- 		return (ARCHIVE_FATAL);
- 	zip->header_offset = si->pi.pos;
++	if (zip->header_bytes_remaining < rbytes)
++		return (NULL);
++	if (zip->pack_stream_bytes_unconsumed)
++		read_consume(a);
 +
- 	/* Extract a pack stream. */
- 	r = extract_pack_stream(a);
- 	if (r < 0)
- 		return (r);
- 	for (;;) {
++	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 = get_uncompressed_data(a, image, vsize);
- 		if (bytes < 0)
- 			return (r);
- 		if (bytes != vsize) {
- 			if (*image != zip->uncompressed_buffer) {
- 				/* This might happen if the coder was COPY.
- 				 * We have to make sure we read a full plain
- 				 * header image. */
- 				if (NULL==__archive_read_ahead(a, vsize, NULL))
- 					return (ARCHIVE_FATAL);
- 				continue;
- 			} else {
- 				archive_set_error(&a->archive, -1,
- 				    "Malformed 7-Zip archive file");
- 				return (ARCHIVE_FATAL);
- 			}
- 		}
- 		break;
- 	}
- 	v = *image;
- 
- 	/* Clean up variables which will not 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;
 +
- 	/* Check the header CRC. */
- 	if (si->ci.folders[0].digest_defined){
- 		uint32_t c = crc32(0, v, vsize);
- 		if (c != si->ci.folders[0].digest) {
- 			archive_set_error(&a->archive, -1, "Header CRC error");
- 			return (ARCHIVE_FATAL);
- 		}
++		bytes = read_stream(a, &buff, rbytes, rbytes);
++		if (bytes <= 0)
++			return (NULL);
++		zip->header_bytes_remaining -= bytes;
++		p = buff;
 +	}
- 	return ((ssize_t)vsize);
++
++	/* 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;
- 	const void *image;
- 	uint64_t len;
 +	uint64_t next_header_offset;
 +	uint64_t next_header_size;
 +	uint32_t next_header_crc;
- 	ssize_t bytes_avail, image_bytes;
- 	int r;
++	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, NULL)) == NULL)
++		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, (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);
 +	}
- 	if (__archive_read_seek(a, next_header_offset + zip->seek_base,
- 	    SEEK_SET) < 0)
- 		return (ARCHIVE_FATAL);
++	__archive_read_consume(a, 32);
++	if (next_header_offset != 0) {
++		if (bytes_avail >= 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 = __archive_read_ahead(a, next_header_size, NULL)) == NULL)
- 		return (ARCHIVE_FATAL);
- 
- 	if (crc32(0, p, next_header_size) != next_header_crc) {
- 		archive_set_error(&a->archive, -1, "Damaged 7-Zip archive");
++	if ((p = header_bytes(a, 1)) == NULL) {
++		archive_set_error(&a->archive,
++		    ARCHIVE_ERRNO_FILE_FORMAT,
++		    "Truncated 7-Zip file body");
 +		return (ARCHIVE_FATAL);
 +	}
- 
- 	len = next_header_size;
 +	/* Parse ArchiveProperties. */
 +	switch (p[0]) {
 +	case kEncodedHeader:
- 		p++;
- 		len--;
- 
 +		/*
 +		 * The archive has an encoded header and we have to decode it
 +		 * in order to parse the header correctly.
 +		 */
- 		image_bytes =
- 		    decode_header_image(a, zip, &(zip->si), p, len, &image);
++		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 (image_bytes < 0)
++		if (r < 0)
 +			return (ARCHIVE_FATAL);
- 		p = image;
- 		len = image_bytes;
++		zip->header_is_encoded = 1;
++		zip->header_crc32 = 0;
 +		/* FALL THROUGH */
 +	case kHeader:
 +		/*
 +		 * Parse the header.
 +		 */
 +		errno = 0;
- 		r = read_Header(zip, header, p, len);
++		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);
 +		}
- 		if (len - r == 0 || p[r] != kEnd) {
++
++		/*
++		 *  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);
 +	}
- 	zip->stream_offset = -1;
 +
- 	/*
- 	 * If the uncompressed buffer was allocated more than 64K for
- 	 * the header image, release it.
- 	 */
- 	if (zip->uncompressed_buffer != NULL &&
- 	    zip->uncompressed_buffer_size != 64 * 1024) {
- 		free(zip->uncompressed_buffer);
- 		zip->uncompressed_buffer = NULL;
- 		zip->uncompressed_buffer_size = 0;
- 	}
++	/* 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)
++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 == -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)
++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 == -1) {
- 		if (__archive_read_ahead(a, 1, &bytes_avail) == NULL
++		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 > zip->pack_stream_inbytes_remaining)
 +			bytes_avail = zip->pack_stream_inbytes_remaining;
 +		zip->pack_stream_inbytes_remaining -= bytes_avail;
 +		if (bytes_avail > 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 = 64 * 1024;
++		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;
++		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;
 +	uint64_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)
++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);
++			r = extract_pack_stream(a, 0);
 +			if (r < 0)
 +				return (r);
- 			return (get_uncompressed_data(a, buff, size));
++			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);
++			r = extract_pack_stream(a, 0);
 +			if (r < 0)
 +				return (r);
- 			return (get_uncompressed_data(a, buff, size));
++			return (get_uncompressed_data(a, buff, size, minimum));
 +		}
 +	} else
- 		return (get_uncompressed_data(a, buff, size));
++		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);
++	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);
++				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);
++				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);
++		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));
++	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] == -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);
++				r = extract_pack_stream(a, 0);
 +				if (r < 0)
 +					return (r);
 +				bytes = get_uncompressed_data(a, &buff,
- 				    zip->uncompressed_buffer_bytes_remaining);
++				    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);
++		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 const unsigned char kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
- static const unsigned char kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
++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(uint8_t *data, size_t size, uint32_t ip, uint32_t *state)
++x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
 +{
- 	size_t bufferPos = 0, prevPosT;
- 	uint32_t prevMask = *state & 0x7;
++	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;
- 	ip += 5;
- 	prevPosT = (size_t)0 - 1;
++
++	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 index;
 +
 +				dest = src - (ip + (uint32_t)bufferPos);
 +				if (prevMask == 0)
 +					break;
 +				index = kMaskToBitNumber[prevMask] * 8;
 +				b = (uint8_t)(dest >> (24 - index));
 +				if (!Test86MSByte(b))
 +					break;
 +				src = dest ^ ((1 << (32 - 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++;
 +		}
 +	}
- 	prevPosT = bufferPos - prevPosT;
- 	*state = ((prevPosT > 3) ? 
- 			0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
++	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 i; for (i = 0; i < 5; i++) { 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;
 +
- ssize_t
++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 b = buf0[inPos];
 +				outBuf[outPos++] = b;
 +				if (IsJ(zip->bcj2_prevByte, b)) {
 +					zip->bcj_state = 2;
 +					break;
 +				}
 +				inPos++;
 +				zip->bcj2_prevByte = b;
 +				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 --cc Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
index 8d2ba1d,0000000..db7aa9d
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
@@@ -1,3213 -1,0 +1,3213 @@@
 +/*-
 + * Copyright (c) 2003-2007 Tim Kientzle
 + * Copyright (c) 2009 Andreas Henriksson <andreas at fatal.se>
 + * 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: head/lib/libarchive/archive_read_support_format_iso9660.c 201246 2009-12-30 05:30:35Z kientzle $");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +/* #include <stdint.h> */ /* See archive_platform.h */
 +#include <stdio.h>
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STRING_H
 +#include <string.h>
 +#endif
 +#include <time.h>
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_endian.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_private.h"
 +#include "archive_read_private.h"
 +#include "archive_string.h"
 +
 +/*
 + * An overview of ISO 9660 format:
 + *
 + * Each disk is laid out as follows:
 + *   * 32k reserved for private use
 + *   * Volume descriptor table.  Each volume descriptor
 + *     is 2k and specifies basic format information.
 + *     The "Primary Volume Descriptor" (PVD) is defined by the
 + *     standard and should always be present; other volume
 + *     descriptors include various vendor-specific extensions.
 + *   * Files and directories.  Each file/dir is specified by
 + *     an "extent" (starting sector and length in bytes).
 + *     Dirs are just files with directory records packed one
 + *     after another.  The PVD contains a single dir entry
 + *     specifying the location of the root directory.  Everything
 + *     else follows from there.
 + *
 + * This module works by first reading the volume descriptors, then
 + * building a list of directory entries, sorted by starting
 + * sector.  At each step, I look for the earliest dir entry that
 + * hasn't yet been read, seek forward to that location and read
 + * that entry.  If it's a dir, I slurp in the new dir entries and
 + * add them to the heap; if it's a regular file, I return the
 + * corresponding archive_entry and wait for the client to request
 + * the file body.  This strategy allows us to read most compliant
 + * CDs with a single pass through the data, as required by libarchive.
 + */
 +#define	LOGICAL_BLOCK_SIZE	2048
 +#define	SYSTEM_AREA_BLOCK	16
 +
 +/* Structure of on-disk primary volume descriptor. */
 +#define PVD_type_offset 0
 +#define PVD_type_size 1
 +#define PVD_id_offset (PVD_type_offset + PVD_type_size)
 +#define PVD_id_size 5
 +#define PVD_version_offset (PVD_id_offset + PVD_id_size)
 +#define PVD_version_size 1
 +#define PVD_reserved1_offset (PVD_version_offset + PVD_version_size)
 +#define PVD_reserved1_size 1
 +#define PVD_system_id_offset (PVD_reserved1_offset + PVD_reserved1_size)
 +#define PVD_system_id_size 32
 +#define PVD_volume_id_offset (PVD_system_id_offset + PVD_system_id_size)
 +#define PVD_volume_id_size 32
 +#define PVD_reserved2_offset (PVD_volume_id_offset + PVD_volume_id_size)
 +#define PVD_reserved2_size 8
 +#define PVD_volume_space_size_offset (PVD_reserved2_offset + PVD_reserved2_size)
 +#define PVD_volume_space_size_size 8
 +#define PVD_reserved3_offset (PVD_volume_space_size_offset + PVD_volume_space_size_size)
 +#define PVD_reserved3_size 32
 +#define PVD_volume_set_size_offset (PVD_reserved3_offset + PVD_reserved3_size)
 +#define PVD_volume_set_size_size 4
 +#define PVD_volume_sequence_number_offset (PVD_volume_set_size_offset + PVD_volume_set_size_size)
 +#define PVD_volume_sequence_number_size 4
 +#define PVD_logical_block_size_offset (PVD_volume_sequence_number_offset + PVD_volume_sequence_number_size)
 +#define PVD_logical_block_size_size 4
 +#define PVD_path_table_size_offset (PVD_logical_block_size_offset + PVD_logical_block_size_size)
 +#define PVD_path_table_size_size 8
 +#define PVD_type_1_path_table_offset (PVD_path_table_size_offset + PVD_path_table_size_size)
 +#define PVD_type_1_path_table_size 4
 +#define PVD_opt_type_1_path_table_offset (PVD_type_1_path_table_offset + PVD_type_1_path_table_size)
 +#define PVD_opt_type_1_path_table_size 4
 +#define PVD_type_m_path_table_offset (PVD_opt_type_1_path_table_offset + PVD_opt_type_1_path_table_size)
 +#define PVD_type_m_path_table_size 4
 +#define PVD_opt_type_m_path_table_offset (PVD_type_m_path_table_offset + PVD_type_m_path_table_size)
 +#define PVD_opt_type_m_path_table_size 4
 +#define PVD_root_directory_record_offset (PVD_opt_type_m_path_table_offset + PVD_opt_type_m_path_table_size)
 +#define PVD_root_directory_record_size 34
 +#define PVD_volume_set_id_offset (PVD_root_directory_record_offset + PVD_root_directory_record_size)
 +#define PVD_volume_set_id_size 128
 +#define PVD_publisher_id_offset (PVD_volume_set_id_offset + PVD_volume_set_id_size)
 +#define PVD_publisher_id_size 128
 +#define PVD_preparer_id_offset (PVD_publisher_id_offset + PVD_publisher_id_size)
 +#define PVD_preparer_id_size 128
 +#define PVD_application_id_offset (PVD_preparer_id_offset + PVD_preparer_id_size)
 +#define PVD_application_id_size 128
 +#define PVD_copyright_file_id_offset (PVD_application_id_offset + PVD_application_id_size)
 +#define PVD_copyright_file_id_size 37
 +#define PVD_abstract_file_id_offset (PVD_copyright_file_id_offset + PVD_copyright_file_id_size)
 +#define PVD_abstract_file_id_size 37
 +#define PVD_bibliographic_file_id_offset (PVD_abstract_file_id_offset + PVD_abstract_file_id_size)
 +#define PVD_bibliographic_file_id_size 37
 +#define PVD_creation_date_offset (PVD_bibliographic_file_id_offset + PVD_bibliographic_file_id_size)
 +#define PVD_creation_date_size 17
 +#define PVD_modification_date_offset (PVD_creation_date_offset + PVD_creation_date_size)
 +#define PVD_modification_date_size 17
 +#define PVD_expiration_date_offset (PVD_modification_date_offset + PVD_modification_date_size)
 +#define PVD_expiration_date_size 17
 +#define PVD_effective_date_offset (PVD_expiration_date_offset + PVD_expiration_date_size)
 +#define PVD_effective_date_size 17
 +#define PVD_file_structure_version_offset (PVD_effective_date_offset + PVD_effective_date_size)
 +#define PVD_file_structure_version_size 1
 +#define PVD_reserved4_offset (PVD_file_structure_version_offset + PVD_file_structure_version_size)
 +#define PVD_reserved4_size 1
 +#define PVD_application_data_offset (PVD_reserved4_offset + PVD_reserved4_size)
 +#define PVD_application_data_size 512
 +#define PVD_reserved5_offset (PVD_application_data_offset + PVD_application_data_size)
 +#define PVD_reserved5_size (2048 - PVD_reserved5_offset)
 +
 +/* TODO: It would make future maintenance easier to just hardcode the
 + * above values.  In particular, ECMA119 states the offsets as part of
 + * the standard.  That would eliminate the need for the following check.*/
 +#if PVD_reserved5_offset != 1395
 +#error PVD offset and size definitions are wrong.
 +#endif
 +
 +
 +/* Structure of optional on-disk supplementary volume descriptor. */
 +#define SVD_type_offset 0
 +#define SVD_type_size 1
 +#define SVD_id_offset (SVD_type_offset + SVD_type_size)
 +#define SVD_id_size 5
 +#define SVD_version_offset (SVD_id_offset + SVD_id_size)
 +#define SVD_version_size 1
 +/* ... */
 +#define SVD_reserved1_offset	72
 +#define SVD_reserved1_size	8
 +#define SVD_volume_space_size_offset 80
 +#define SVD_volume_space_size_size 8
 +#define SVD_escape_sequences_offset (SVD_volume_space_size_offset + SVD_volume_space_size_size)
 +#define SVD_escape_sequences_size 32
 +/* ... */
 +#define SVD_logical_block_size_offset 128
 +#define SVD_logical_block_size_size 4
 +#define SVD_type_L_path_table_offset 140
 +#define SVD_type_M_path_table_offset 148
 +/* ... */
 +#define SVD_root_directory_record_offset 156
 +#define SVD_root_directory_record_size 34
 +#define SVD_file_structure_version_offset 881
 +#define SVD_reserved2_offset	882
 +#define SVD_reserved2_size	1
 +#define SVD_reserved3_offset	1395
 +#define SVD_reserved3_size	653
 +/* ... */
 +/* FIXME: validate correctness of last SVD entry offset. */
 +
 +/* Structure of an on-disk directory record. */
 +/* Note:  ISO9660 stores each multi-byte integer twice, once in
 + * each byte order.  The sizes here are the size of just one
 + * of the two integers.  (This is why the offset of a field isn't
 + * the same as the offset+size of the previous field.) */
 +#define DR_length_offset 0
 +#define DR_length_size 1
 +#define DR_ext_attr_length_offset 1
 +#define DR_ext_attr_length_size 1
 +#define DR_extent_offset 2
 +#define DR_extent_size 4
 +#define DR_size_offset 10
 +#define DR_size_size 4
 +#define DR_date_offset 18
 +#define DR_date_size 7
 +#define DR_flags_offset 25
 +#define DR_flags_size 1
 +#define DR_file_unit_size_offset 26
 +#define DR_file_unit_size_size 1
 +#define DR_interleave_offset 27
 +#define DR_interleave_size 1
 +#define DR_volume_sequence_number_offset 28
 +#define DR_volume_sequence_number_size 2
 +#define DR_name_len_offset 32
 +#define DR_name_len_size 1
 +#define DR_name_offset 33
 +
 +#ifdef HAVE_ZLIB_H
 +static const unsigned char zisofs_magic[8] = {
 +	0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07
 +};
 +
 +struct zisofs {
 +	/* Set 1 if this file compressed by paged zlib */
 +	int		 pz;
 +	int		 pz_log2_bs; /* Log2 of block size */
 +	uint64_t	 pz_uncompressed_size;
 +
 +	int		 initialized;
 +	unsigned char	*uncompressed_buffer;
 +	size_t		 uncompressed_buffer_size;
 +
 +	uint32_t	 pz_offset;
 +	unsigned char	 header[16];
 +	size_t		 header_avail;
 +	int		 header_passed;
 +	unsigned char	*block_pointers;
 +	size_t		 block_pointers_alloc;
 +	size_t		 block_pointers_size;
 +	size_t		 block_pointers_avail;
 +	size_t		 block_off;
 +	uint32_t	 block_avail;
 +
 +	z_stream	 stream;
 +	int		 stream_valid;
 +};
 +#else
 +struct zisofs {
 +	/* Set 1 if this file compressed by paged zlib */
 +	int		 pz;
 +};
 +#endif
 +
 +struct content {
 +	uint64_t	 offset;/* Offset on disk.		*/
 +	uint64_t	 size;	/* File size in bytes.		*/
 +	struct content	*next;
 +};
 +
 +/* In-memory storage for a directory record. */
 +struct file_info {
 +	struct file_info	*use_next;
 +	struct file_info	*parent;
 +	struct file_info	*next;
 +	struct file_info	*re_next;
 +	int		 subdirs;
 +	uint64_t	 key;		/* Heap Key.			*/
 +	uint64_t	 offset;	/* Offset on disk.		*/
 +	uint64_t	 size;		/* File size in bytes.		*/
 +	uint32_t	 ce_offset;	/* Offset of CE.		*/
 +	uint32_t	 ce_size;	/* Size of CE.			*/
 +	char		 rr_moved;	/* Flag to rr_moved.		*/
 +	char		 rr_moved_has_re_only;
 +	char		 re;		/* Having RRIP "RE" extension.	*/
 +	char		 re_descendant;
 +	uint64_t	 cl_offset;	/* Having RRIP "CL" extension.	*/
 +	int		 birthtime_is_set;
 +	time_t		 birthtime;	/* File created time.		*/
 +	time_t		 mtime;		/* File last modified time.	*/
 +	time_t		 atime;		/* File last accessed time.	*/
 +	time_t		 ctime;		/* File attribute change time.	*/
 +	uint64_t	 rdev;		/* Device number.		*/
 +	mode_t		 mode;
 +	uid_t		 uid;
 +	gid_t		 gid;
 +	int64_t		 number;
 +	int		 nlinks;
 +	struct archive_string name; /* Pathname */
 +	unsigned char	*utf16be_name;
 +	size_t		 utf16be_bytes;
 +	char		 name_continues; /* Non-zero if name continues */
 +	struct archive_string symlink;
 +	char		 symlink_continues; /* Non-zero if link continues */
 +	/* Set 1 if this file compressed by paged zlib(zisofs) */
 +	int		 pz;
 +	int		 pz_log2_bs; /* Log2 of block size */
 +	uint64_t	 pz_uncompressed_size;
 +	/* Set 1 if this file is multi extent. */
 +	int		 multi_extent;
 +	struct {
 +		struct content	*first;
 +		struct content	**last;
 +	} contents;
 +	struct {
 +		struct file_info	*first;
 +		struct file_info	**last;
 +	} rede_files;
 +};
 +
 +struct heap_queue {
 +	struct file_info **files;
 +	int		 allocated;
 +	int		 used;
 +};
 +
 +struct iso9660 {
 +	int	magic;
 +#define ISO9660_MAGIC   0x96609660
 +
 +	int opt_support_joliet;
 +	int opt_support_rockridge;
 +
 +	struct archive_string pathname;
 +	char	seenRockridge;	/* Set true if RR extensions are used. */
 +	char	seenSUSP;	/* Set true if SUSP is beging used. */
 +	char	seenJoliet;
 +
 +	unsigned char	suspOffset;
 +	struct file_info *rr_moved;
 +	struct read_ce_queue {
 +		struct read_ce_req {
 +			uint64_t	 offset;/* Offset of CE on disk. */
 +			struct file_info *file;
 +		}		*reqs;
 +		int		 cnt;
 +		int		 allocated;
 +	}	read_ce_req;
 +
 +	int64_t		previous_number;
 +	struct archive_string previous_pathname;
 +
 +	struct file_info		*use_files;
 +	struct heap_queue		 pending_files;
 +	struct {
 +		struct file_info	*first;
 +		struct file_info	**last;
 +	}	cache_files;
 +	struct {
 +		struct file_info	*first;
 +		struct file_info	**last;
 +	}	re_files;
 +
 +	uint64_t current_position;
 +	ssize_t	logical_block_size;
 +	uint64_t volume_size; /* Total size of volume in bytes. */
 +	int32_t  volume_block;/* Total size of volume in logical blocks. */
 +
 +	struct vd {
 +		int		location;	/* Location of Extent.	*/
 +		uint32_t	size;
 +	} primary, joliet;
 +
 +	int64_t	entry_sparse_offset;
 +	int64_t	entry_bytes_remaining;
 +	size_t  entry_bytes_unconsumed;
 +	struct zisofs	 entry_zisofs;
 +	struct content	*entry_content;
 +	struct archive_string_conv *sconv_utf16be;
 +	/*
 +	 * Buffers for a full pathname in UTF-16BE in Joliet extensions.
 +	 */
 +#define UTF16_NAME_MAX	1024
 +	unsigned char *utf16be_path;
 +	size_t		 utf16be_path_len;
 +	unsigned char *utf16be_previous_path;
 +	size_t		 utf16be_previous_path_len;
 +};
 +
 +static int	archive_read_format_iso9660_bid(struct archive_read *, int);
 +static int	archive_read_format_iso9660_options(struct archive_read *,
 +		    const char *, const char *);
 +static int	archive_read_format_iso9660_cleanup(struct archive_read *);
 +static int	archive_read_format_iso9660_read_data(struct archive_read *,
 +		    const void **, size_t *, int64_t *);
 +static int	archive_read_format_iso9660_read_data_skip(struct archive_read *);
 +static int	archive_read_format_iso9660_read_header(struct archive_read *,
 +		    struct archive_entry *);
 +static const char *build_pathname(struct archive_string *, struct file_info *);
 +static int	build_pathname_utf16be(unsigned char *, size_t, size_t *,
 +		    struct file_info *);
 +#if DEBUG
 +static void	dump_isodirrec(FILE *, const unsigned char *isodirrec);
 +#endif
 +static time_t	time_from_tm(struct tm *);
 +static time_t	isodate17(const unsigned char *);
 +static time_t	isodate7(const unsigned char *);
 +static int	isBootRecord(struct iso9660 *, const unsigned char *);
 +static int	isVolumePartition(struct iso9660 *, const unsigned char *);
 +static int	isVDSetTerminator(struct iso9660 *, const unsigned char *);
 +static int	isJolietSVD(struct iso9660 *, const unsigned char *);
 +static int	isSVD(struct iso9660 *, const unsigned char *);
 +static int	isEVD(struct iso9660 *, const unsigned char *);
 +static int	isPVD(struct iso9660 *, const unsigned char *);
 +static int	next_cache_entry(struct archive_read *, struct iso9660 *,
 +		    struct file_info **);
 +static int	next_entry_seek(struct archive_read *, struct iso9660 *,
 +		    struct file_info **);
 +static struct file_info *
 +		parse_file_info(struct archive_read *a,
 +		    struct file_info *parent, const unsigned char *isodirrec);
 +static int	parse_rockridge(struct archive_read *a,
 +		    struct file_info *file, const unsigned char *start,
 +		    const unsigned char *end);
 +static int	register_CE(struct archive_read *a, int32_t location,
 +		    struct file_info *file);
 +static int	read_CE(struct archive_read *a, struct iso9660 *iso9660);
 +static void	parse_rockridge_NM1(struct file_info *,
 +		    const unsigned char *, int);
 +static void	parse_rockridge_SL1(struct file_info *,
 +		    const unsigned char *, int);
 +static void	parse_rockridge_TF1(struct file_info *,
 +		    const unsigned char *, int);
 +static void	parse_rockridge_ZF1(struct file_info *,
 +		    const unsigned char *, int);
 +static void	register_file(struct iso9660 *, struct file_info *);
 +static void	release_files(struct iso9660 *);
 +static unsigned	toi(const void *p, int n);
 +static inline void re_add_entry(struct iso9660 *, struct file_info *);
 +static inline struct file_info * re_get_entry(struct iso9660 *);
 +static inline int rede_add_entry(struct file_info *);
 +static inline struct file_info * rede_get_entry(struct file_info *);
 +static inline void cache_add_entry(struct iso9660 *iso9660,
 +		    struct file_info *file);
 +static inline struct file_info *cache_get_entry(struct iso9660 *iso9660);
 +static int	heap_add_entry(struct archive_read *a, struct heap_queue *heap,
 +		    struct file_info *file, uint64_t key);
 +static struct file_info *heap_get_entry(struct heap_queue *heap);
 +
 +#define add_entry(arch, iso9660, file)	\
 +	heap_add_entry(arch, &((iso9660)->pending_files), file, file->offset)
 +#define next_entry(iso9660)		\
 +	heap_get_entry(&((iso9660)->pending_files))
 +
 +int
 +archive_read_support_format_iso9660(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct iso9660 *iso9660;
 +	int r;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_read_support_format_iso9660");
 +
 +	iso9660 = (struct iso9660 *)calloc(1, sizeof(*iso9660));
 +	if (iso9660 == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate iso9660 data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	iso9660->magic = ISO9660_MAGIC;
 +	iso9660->cache_files.first = NULL;
 +	iso9660->cache_files.last = &(iso9660->cache_files.first);
 +	iso9660->re_files.first = NULL;
 +	iso9660->re_files.last = &(iso9660->re_files.first);
 +	/* Enable to support Joliet extensions by default.	*/
 +	iso9660->opt_support_joliet = 1;
 +	/* Enable to support Rock Ridge extensions by default.	*/
 +	iso9660->opt_support_rockridge = 1;
 +
 +	r = __archive_read_register_format(a,
 +	    iso9660,
 +	    "iso9660",
 +	    archive_read_format_iso9660_bid,
 +	    archive_read_format_iso9660_options,
 +	    archive_read_format_iso9660_read_header,
 +	    archive_read_format_iso9660_read_data,
 +	    archive_read_format_iso9660_read_data_skip,
 +	    archive_read_format_iso9660_cleanup);
 +
 +	if (r != ARCHIVE_OK) {
 +		free(iso9660);
 +		return (r);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +
 +static int
 +archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
 +{
 +	struct iso9660 *iso9660;
 +	ssize_t bytes_read;
 +	const unsigned char *p;
 +	int seenTerminator;
 +
 +	/* If there's already a better bid than we can ever
 +	   make, don't bother testing. */
 +	if (best_bid > 48)
 +		return (-1);
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +
 +	/*
 +	 * Skip the first 32k (reserved area) and get the first
 +	 * 8 sectors of the volume descriptor table.  Of course,
 +	 * if the I/O layer gives us more, we'll take it.
 +	 */
 +#define RESERVED_AREA	(SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE)
 +	p = __archive_read_ahead(a,
 +	    RESERVED_AREA + 8 * LOGICAL_BLOCK_SIZE,
 +	    &bytes_read);
 +	if (p == NULL)
 +	    return (-1);
 +
 +	/* Skip the reserved area. */
 +	bytes_read -= RESERVED_AREA;
 +	p += RESERVED_AREA;
 +
 +	/* Check each volume descriptor. */
 +	seenTerminator = 0;
 +	for (; bytes_read > LOGICAL_BLOCK_SIZE;
 +	    bytes_read -= LOGICAL_BLOCK_SIZE, p += LOGICAL_BLOCK_SIZE) {
 +		/* Do not handle undefined Volume Descriptor Type. */
 +		if (p[0] >= 4 && p[0] <= 254)
 +			return (0);
 +		/* Standard Identifier must be "CD001" */
 +		if (memcmp(p + 1, "CD001", 5) != 0)
 +			return (0);
 +		if (isPVD(iso9660, p))
 +			continue;
 +		if (!iso9660->joliet.location) {
 +			if (isJolietSVD(iso9660, p))
 +				continue;
 +		}
 +		if (isBootRecord(iso9660, p))
 +			continue;
 +		if (isEVD(iso9660, p))
 +			continue;
 +		if (isSVD(iso9660, p))
 +			continue;
 +		if (isVolumePartition(iso9660, p))
 +			continue;
 +		if (isVDSetTerminator(iso9660, p)) {
 +			seenTerminator = 1;
 +			break;
 +		}
 +		return (0);
 +	}
 +	/*
 +	 * ISO 9660 format must have Primary Volume Descriptor and
 +	 * Volume Descriptor Set Terminator.
 +	 */
 +	if (seenTerminator && iso9660->primary.location > 16)
 +		return (48);
 +
 +	/* We didn't find a valid PVD; return a bid of zero. */
 +	return (0);
 +}
 +
 +static int
 +archive_read_format_iso9660_options(struct archive_read *a,
 +		const char *key, const char *val)
 +{
 +	struct iso9660 *iso9660;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +
 +	if (strcmp(key, "joliet") == 0) {
 +		if (val == NULL || strcmp(val, "off") == 0 ||
 +				strcmp(val, "ignore") == 0 ||
 +				strcmp(val, "disable") == 0 ||
 +				strcmp(val, "0") == 0)
 +			iso9660->opt_support_joliet = 0;
 +		else
 +			iso9660->opt_support_joliet = 1;
 +		return (ARCHIVE_OK);
 +	}
 +	if (strcmp(key, "rockridge") == 0 ||
 +	    strcmp(key, "Rockridge") == 0) {
 +		iso9660->opt_support_rockridge = val != NULL;
 +		return (ARCHIVE_OK);
 +	}
 +
 +	/* 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
 +isBootRecord(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	(void)iso9660; /* UNUSED */
 +
 +	/* Type of the Volume Descriptor Boot Record must be 0. */
 +	if (h[0] != 0)
 +		return (0);
 +
 +	/* Volume Descriptor Version must be 1. */
 +	if (h[6] != 1)
 +		return (0);
 +
 +	return (1);
 +}
 +
 +static int
 +isVolumePartition(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	int32_t location;
 +
 +	/* Type of the Volume Partition Descriptor must be 3. */
 +	if (h[0] != 3)
 +		return (0);
 +
 +	/* Volume Descriptor Version must be 1. */
 +	if (h[6] != 1)
 +		return (0);
 +	/* Unused Field */
 +	if (h[7] != 0)
 +		return (0);
 +
 +	location = archive_le32dec(h + 72);
 +	if (location <= SYSTEM_AREA_BLOCK ||
 +	    location >= iso9660->volume_block)
 +		return (0);
 +	if ((uint32_t)location != archive_be32dec(h + 76))
 +		return (0);
 +
 +	return (1);
 +}
 +
 +static int
 +isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	int i;
 +
 +	(void)iso9660; /* UNUSED */
 +
 +	/* Type of the Volume Descriptor Set Terminator must be 255. */
 +	if (h[0] != 255)
 +		return (0);
 +
 +	/* Volume Descriptor Version must be 1. */
 +	if (h[6] != 1)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
 +	for (i = 7; i < 2048; ++i)
 +		if (h[i] != 0)
 +			return (0);
 +
 +	return (1);
 +}
 +
 +static int
 +isJolietSVD(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	const unsigned char *p;
 +	ssize_t logical_block_size;
 +	int32_t volume_block;
 +
 +	/* Check if current sector is a kind of Supplementary Volume
 +	 * Descriptor. */
 +	if (!isSVD(iso9660, h))
 +		return (0);
 +
 +	/* FIXME: do more validations according to joliet spec. */
 +
 +	/* check if this SVD contains joliet extension! */
 +	p = h + SVD_escape_sequences_offset;
 +	/* N.B. Joliet spec says p[1] == '\\', but.... */
 +	if (p[0] == '%' && p[1] == '/') {
 +		int level = 0;
 +
 +		if (p[2] == '@')
 +			level = 1;
 +		else if (p[2] == 'C')
 +			level = 2;
 +		else if (p[2] == 'E')
 +			level = 3;
 +		else /* not joliet */
 +			return (0);
 +
 +		iso9660->seenJoliet = level;
 +
 +	} else /* not joliet */
 +		return (0);
 +
 +	logical_block_size =
 +	    archive_le16dec(h + SVD_logical_block_size_offset);
 +	volume_block = archive_le32dec(h + SVD_volume_space_size_offset);
 +
 +	iso9660->logical_block_size = logical_block_size;
 +	iso9660->volume_block = volume_block;
 +	iso9660->volume_size = logical_block_size * (uint64_t)volume_block;
 +	/* Read Root Directory Record in Volume Descriptor. */
 +	p = h + SVD_root_directory_record_offset;
 +	iso9660->joliet.location = archive_le32dec(p + DR_extent_offset);
 +	iso9660->joliet.size = archive_le32dec(p + DR_size_offset);
 +
 +	return (48);
 +}
 +
 +static int
 +isSVD(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	const unsigned char *p;
 +	ssize_t logical_block_size;
 +	int32_t volume_block;
 +	int32_t location;
 +	int i;
 +
 +	(void)iso9660; /* UNUSED */
 +
 +	/* Type 2 means it's a SVD. */
 +	if (h[SVD_type_offset] != 2)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
 +	for (i = 0; i < SVD_reserved1_size; ++i)
 +		if (h[SVD_reserved1_offset + i] != 0)
 +			return (0);
 +	for (i = 0; i < SVD_reserved2_size; ++i)
 +		if (h[SVD_reserved2_offset + i] != 0)
 +			return (0);
 +	for (i = 0; i < SVD_reserved3_size; ++i)
 +		if (h[SVD_reserved3_offset + i] != 0)
 +			return (0);
 +
 +	/* File structure version must be 1 for ISO9660/ECMA119. */
 +	if (h[SVD_file_structure_version_offset] != 1)
 +		return (0);
 +
 +	logical_block_size =
 +	    archive_le16dec(h + SVD_logical_block_size_offset);
 +	if (logical_block_size <= 0)
 +		return (0);
 +
 +	volume_block = archive_le32dec(h + SVD_volume_space_size_offset);
 +	if (volume_block <= SYSTEM_AREA_BLOCK+4)
 +		return (0);
 +
 +	/* Location of Occurrence of Type L Path Table must be
 +	 * available location,
 +	 * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_le32dec(h+SVD_type_L_path_table_offset);
 +	if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)
 +		return (0);
 +
 +	/* The Type M Path Table must be at a valid location (WinISO
 +	 * and probably other programs omit this, so we allow zero)
 +	 *
 +	 * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_be32dec(h+SVD_type_M_path_table_offset);
 +	if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)
 +	    || location >= volume_block)
 +		return (0);
 +
 +	/* Read Root Directory Record in Volume Descriptor. */
 +	p = h + SVD_root_directory_record_offset;
 +	if (p[DR_length_offset] != 34)
 +		return (0);
 +
 +	return (48);
 +}
 +
 +static int
 +isEVD(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	const unsigned char *p;
 +	ssize_t logical_block_size;
 +	int32_t volume_block;
 +	int32_t location;
 +	int i;
 +
 +	(void)iso9660; /* UNUSED */
 +
 +	/* Type of the Enhanced Volume Descriptor must be 2. */
 +	if (h[PVD_type_offset] != 2)
 +		return (0);
 +
 +	/* EVD version must be 2. */
 +	if (h[PVD_version_offset] != 2)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
 +	if (h[PVD_reserved1_offset] != 0)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
 +	for (i = 0; i < PVD_reserved2_size; ++i)
 +		if (h[PVD_reserved2_offset + i] != 0)
 +			return (0);
 +
 +	/* Reserved field must be 0. */
 +	for (i = 0; i < PVD_reserved3_size; ++i)
 +		if (h[PVD_reserved3_offset + i] != 0)
 +			return (0);
 +
 +	/* Logical block size must be > 0. */
 +	/* I've looked at Ecma 119 and can't find any stronger
 +	 * restriction on this field. */
 +	logical_block_size =
 +	    archive_le16dec(h + PVD_logical_block_size_offset);
 +	if (logical_block_size <= 0)
 +		return (0);
 +
 +	volume_block =
 +	    archive_le32dec(h + PVD_volume_space_size_offset);
 +	if (volume_block <= SYSTEM_AREA_BLOCK+4)
 +		return (0);
 +
 +	/* File structure version must be 2 for ISO9660:1999. */
 +	if (h[PVD_file_structure_version_offset] != 2)
 +		return (0);
 +
 +	/* Location of Occurrence of Type L Path Table must be
 +	 * available location,
 +	 * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_le32dec(h+PVD_type_1_path_table_offset);
 +	if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)
 +		return (0);
 +
 +	/* Location of Occurrence of Type M Path Table must be
 +	 * available location,
 +	 * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_be32dec(h+PVD_type_m_path_table_offset);
 +	if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)
 +	    || location >= volume_block)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
 +	for (i = 0; i < PVD_reserved4_size; ++i)
 +		if (h[PVD_reserved4_offset + i] != 0)
 +			return (0);
 +
 +	/* Reserved field must be 0. */
 +	for (i = 0; i < PVD_reserved5_size; ++i)
 +		if (h[PVD_reserved5_offset + i] != 0)
 +			return (0);
 +
 +	/* Read Root Directory Record in Volume Descriptor. */
 +	p = h + PVD_root_directory_record_offset;
 +	if (p[DR_length_offset] != 34)
 +		return (0);
 +
 +	return (48);
 +}
 +
 +static int
 +isPVD(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	const unsigned char *p;
 +	ssize_t logical_block_size;
 +	int32_t volume_block;
 +	int32_t location;
 +	int i;
 +
 +	/* Type of the Primary Volume Descriptor must be 1. */
 +	if (h[PVD_type_offset] != 1)
 +		return (0);
 +
 +	/* PVD version must be 1. */
 +	if (h[PVD_version_offset] != 1)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
 +	if (h[PVD_reserved1_offset] != 0)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
 +	for (i = 0; i < PVD_reserved2_size; ++i)
 +		if (h[PVD_reserved2_offset + i] != 0)
 +			return (0);
 +
 +	/* Reserved field must be 0. */
 +	for (i = 0; i < PVD_reserved3_size; ++i)
 +		if (h[PVD_reserved3_offset + i] != 0)
 +			return (0);
 +
 +	/* Logical block size must be > 0. */
 +	/* I've looked at Ecma 119 and can't find any stronger
 +	 * restriction on this field. */
 +	logical_block_size =
 +	    archive_le16dec(h + PVD_logical_block_size_offset);
 +	if (logical_block_size <= 0)
 +		return (0);
 +
 +	volume_block = archive_le32dec(h + PVD_volume_space_size_offset);
 +	if (volume_block <= SYSTEM_AREA_BLOCK+4)
 +		return (0);
 +
 +	/* File structure version must be 1 for ISO9660/ECMA119. */
 +	if (h[PVD_file_structure_version_offset] != 1)
 +		return (0);
 +
 +	/* Location of Occurrence of Type L Path Table must be
 +	 * available location,
 +	 * > SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_le32dec(h+PVD_type_1_path_table_offset);
 +	if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)
 +		return (0);
 +
 +	/* The Type M Path Table must also be at a valid location
 +	 * (although ECMA 119 requires a Type M Path Table, WinISO and
 +	 * probably other programs omit it, so we permit a zero here)
 +	 *
 +	 * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_be32dec(h+PVD_type_m_path_table_offset);
 +	if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)
 +	    || location >= volume_block)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
 +	/* But accept NetBSD/FreeBSD "makefs" images with 0x20 here. */
 +	for (i = 0; i < PVD_reserved4_size; ++i)
 +		if (h[PVD_reserved4_offset + i] != 0
 +		    && h[PVD_reserved4_offset + i] != 0x20)
 +			return (0);
 +
 +	/* Reserved field must be 0. */
 +	for (i = 0; i < PVD_reserved5_size; ++i)
 +		if (h[PVD_reserved5_offset + i] != 0)
 +			return (0);
 +
 +	/* XXX TODO: Check other values for sanity; reject more
 +	 * malformed PVDs. XXX */
 +
 +	/* Read Root Directory Record in Volume Descriptor. */
 +	p = h + PVD_root_directory_record_offset;
 +	if (p[DR_length_offset] != 34)
 +		return (0);
 +
 +	if (!iso9660->primary.location) {
 +		iso9660->logical_block_size = logical_block_size;
 +		iso9660->volume_block = volume_block;
 +		iso9660->volume_size = logical_block_size * (uint64_t)volume_block;
 +		iso9660->primary.location = archive_le32dec(p + DR_extent_offset);
 +		iso9660->primary.size = archive_le32dec(p + DR_size_offset);
 +	}
 +
 +	return (48);
 +}
 +
 +static int
 +read_children(struct archive_read *a, struct file_info *parent)
 +{
 +	struct iso9660 *iso9660;
 +	const unsigned char *b, *p;
 +	struct file_info *multi;
 +	size_t step, skip_size;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +	if (iso9660->current_position > parent->offset) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Ignoring out-of-order directory (%s) %jd > %jd",
 +		    parent->name.s,
 +		    (intmax_t)iso9660->current_position,
 +		    (intmax_t)parent->offset);
 +		return (ARCHIVE_WARN);
 +	}
 +	if (parent->offset + parent->size > iso9660->volume_size) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Directory is beyond end-of-media: %s",
 +		    parent->name.s);
 +		return (ARCHIVE_WARN);
 +	}
 +	if (iso9660->current_position < parent->offset) {
 +		int64_t skipsize;
 +
 +		skipsize = parent->offset - iso9660->current_position;
 +		skipsize = __archive_read_consume(a, skipsize);
 +		if (skipsize < 0)
 +			return ((int)skipsize);
 +		iso9660->current_position = parent->offset;
 +	}
 +
 +	step = ((parent->size + iso9660->logical_block_size -1) /
 +	    iso9660->logical_block_size) * iso9660->logical_block_size;
 +	b = __archive_read_ahead(a, step, NULL);
 +	if (b == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Failed to read full block when scanning "
 +		    "ISO9660 directory list");
 +		return (ARCHIVE_FATAL);
 +	}
 +	iso9660->current_position += step;
 +	multi = NULL;
 +	skip_size = step;
 +	while (step) {
 +		p = b;
 +		b += iso9660->logical_block_size;
 +		step -= iso9660->logical_block_size;
 +		for (; *p != 0 && p < b && p + *p <= b; p += *p) {
 +			struct file_info *child;
 +
 +			/* N.B.: these special directory identifiers
 +			 * are 8 bit "values" even on a
 +			 * Joliet CD with UCS-2 (16bit) encoding.
 +			 */
 +
 +			/* Skip '.' entry. */
 +			if (*(p + DR_name_len_offset) == 1
 +			    && *(p + DR_name_offset) == '\0')
 +				continue;
 +			/* Skip '..' entry. */
 +			if (*(p + DR_name_len_offset) == 1
 +			    && *(p + DR_name_offset) == '\001')
 +				continue;
 +			child = parse_file_info(a, parent, p);
 +			if (child == NULL) {
 +				__archive_read_consume(a, skip_size);
 +				return (ARCHIVE_FATAL);
 +			}
 +			if (child->cl_offset == 0 &&
 +			    (child->multi_extent || multi != NULL)) {
 +				struct content *con;
 +
 +				if (multi == NULL) {
 +					multi = child;
 +					multi->contents.first = NULL;
 +					multi->contents.last =
 +					    &(multi->contents.first);
 +				}
 +				con = malloc(sizeof(struct content));
 +				if (con == NULL) {
 +					archive_set_error(
 +					    &a->archive, ENOMEM,
 +					    "No memory for multi extent");
 +					__archive_read_consume(a, skip_size);
 +					return (ARCHIVE_FATAL);
 +				}
 +				con->offset = child->offset;
 +				con->size = child->size;
 +				con->next = NULL;
 +				*multi->contents.last = con;
 +				multi->contents.last = &(con->next);
 +				if (multi == child) {
 +					if (add_entry(a, iso9660, child)
 +					    != ARCHIVE_OK)
 +						return (ARCHIVE_FATAL);
 +				} else {
 +					multi->size += child->size;
 +					if (!child->multi_extent)
 +						multi = NULL;
 +				}
 +			} else
 +				if (add_entry(a, iso9660, child) != ARCHIVE_OK)
 +					return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	__archive_read_consume(a, skip_size);
 +
 +	/* Read data which recorded by RRIP "CE" extension. */
 +	if (read_CE(a, iso9660) != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_read_format_iso9660_read_header(struct archive_read *a,
 +    struct archive_entry *entry)
 +{
 +	struct iso9660 *iso9660;
 +	struct file_info *file;
 +	int r, rd_r = ARCHIVE_OK;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +
 +	if (!a->archive.archive_format) {
 +		a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
 +		a->archive.archive_format_name = "ISO9660";
 +	}
 +
 +	if (iso9660->current_position == 0) {
 +		int64_t skipsize;
 +		struct vd *vd;
 +		const void *block;
 +		char seenJoliet;
 +
 +		vd = &(iso9660->primary);
 +		if (!iso9660->opt_support_joliet)
 +			iso9660->seenJoliet = 0;
 +		if (iso9660->seenJoliet &&
 +			vd->location > iso9660->joliet.location)
 +			/* This condition is unlikely; by way of caution. */
 +			vd = &(iso9660->joliet);
 +
 +		skipsize = LOGICAL_BLOCK_SIZE * vd->location;
 +		skipsize = __archive_read_consume(a, skipsize);
 +		if (skipsize < 0)
 +			return ((int)skipsize);
 +		iso9660->current_position = skipsize;
 +
 +		block = __archive_read_ahead(a, vd->size, NULL);
 +		if (block == NULL) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Failed to read full block when scanning "
 +			    "ISO9660 directory list");
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		/*
 +		 * While reading Root Directory, flag seenJoliet
 +		 * must be zero to avoid converting special name
 +		 * 0x00(Current Directory) and next byte to UCS2.
 +		 */
 +		seenJoliet = iso9660->seenJoliet;/* Save flag. */
 +		iso9660->seenJoliet = 0;
 +		file = parse_file_info(a, NULL, block);
 +		if (file == NULL)
 +			return (ARCHIVE_FATAL);
 +		iso9660->seenJoliet = seenJoliet;
 +		if (vd == &(iso9660->primary) && iso9660->seenRockridge
 +		    && iso9660->seenJoliet)
 +			/*
 +			 * If iso image has RockRidge and Joliet,
 +			 * we use RockRidge Extensions.
 +			 */
 +			iso9660->seenJoliet = 0;
 +		if (vd == &(iso9660->primary) && !iso9660->seenRockridge
 +		    && iso9660->seenJoliet) {
 +			/* Switch reading data from primary to joliet. */ 
 +			vd = &(iso9660->joliet);
 +			skipsize = LOGICAL_BLOCK_SIZE * vd->location;
 +			skipsize -= iso9660->current_position;
 +			skipsize = __archive_read_consume(a, skipsize);
 +			if (skipsize < 0)
 +				return ((int)skipsize);
 +			iso9660->current_position += skipsize;
 +
 +			block = __archive_read_ahead(a, vd->size, NULL);
 +			if (block == NULL) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Failed to read full block when scanning "
 +				    "ISO9660 directory list");
 +				return (ARCHIVE_FATAL);
 +			}
 +			iso9660->seenJoliet = 0;
 +			file = parse_file_info(a, NULL, block);
 +			if (file == NULL)
 +				return (ARCHIVE_FATAL);
 +			iso9660->seenJoliet = seenJoliet;
 +		}
 +		/* Store the root directory in the pending list. */
 +		if (add_entry(a, iso9660, file) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		if (iso9660->seenRockridge) {
 +			a->archive.archive_format =
 +			    ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;
 +			a->archive.archive_format_name =
 +			    "ISO9660 with Rockridge extensions";
 +		}
 +	}
 +
 +	file = NULL;/* Eliminate a warning. */
 +	/* Get the next entry that appears after the current offset. */
 +	r = next_entry_seek(a, iso9660, &file);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +
 +	if (iso9660->seenJoliet) {
 +		/*
 +		 * Convert UTF-16BE of a filename to local locale MBS
 +		 * and store the result into a filename field.
 +		 */
 +		if (iso9660->sconv_utf16be == NULL) {
 +			iso9660->sconv_utf16be =
 +			    archive_string_conversion_from_charset(
 +				&(a->archive), "UTF-16BE", 1);
 +			if (iso9660->sconv_utf16be == NULL)
 +				/* Coundn't allocate memory */
 +				return (ARCHIVE_FATAL);
 +		}
 +		if (iso9660->utf16be_path == NULL) {
 +			iso9660->utf16be_path = malloc(UTF16_NAME_MAX);
 +			if (iso9660->utf16be_path == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory");
 +				return (ARCHIVE_FATAL);
 +			}
 +		}
 +		if (iso9660->utf16be_previous_path == NULL) {
 +			iso9660->utf16be_previous_path = malloc(UTF16_NAME_MAX);
 +			if (iso9660->utf16be_previous_path == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory");
 +				return (ARCHIVE_FATAL);
 +			}
 +		}
 +
 +		iso9660->utf16be_path_len = 0;
 +		if (build_pathname_utf16be(iso9660->utf16be_path,
 +		    UTF16_NAME_MAX, &(iso9660->utf16be_path_len), file) != 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Pathname is too long");
 +		}
 +
 +		r = archive_entry_copy_pathname_l(entry,
 +		    (const char *)iso9660->utf16be_path,
 +		    iso9660->utf16be_path_len,
 +		    iso9660->sconv_utf16be);
 +		if (r != 0) {
 +			if (errno == ENOMEM) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No 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(
 +			      iso9660->sconv_utf16be));
 +
 +			rd_r = ARCHIVE_WARN;
 +		}
 +	} else {
 +		archive_string_empty(&iso9660->pathname);
 +		archive_entry_set_pathname(entry,
 +		    build_pathname(&iso9660->pathname, file));
 +	}
 +
 +	iso9660->entry_bytes_remaining = file->size;
 +	iso9660->entry_sparse_offset = 0; /* Offset for sparse-file-aware clients. */
 +
 +	if (file->offset + file->size > iso9660->volume_size) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "File is beyond end-of-media: %s",
 +		    archive_entry_pathname(entry));
 +		iso9660->entry_bytes_remaining = 0;
 +		iso9660->entry_sparse_offset = 0;
 +		return (ARCHIVE_WARN);
 +	}
 +
 +	/* Set up the entry structure with information about this entry. */
 +	archive_entry_set_mode(entry, file->mode);
 +	archive_entry_set_uid(entry, file->uid);
 +	archive_entry_set_gid(entry, file->gid);
 +	archive_entry_set_nlink(entry, file->nlinks);
 +	if (file->birthtime_is_set)
 +		archive_entry_set_birthtime(entry, file->birthtime, 0);
 +	else
 +		archive_entry_unset_birthtime(entry);
 +	archive_entry_set_mtime(entry, file->mtime, 0);
 +	archive_entry_set_ctime(entry, file->ctime, 0);
 +	archive_entry_set_atime(entry, file->atime, 0);
 +	/* N.B.: Rock Ridge supports 64-bit device numbers. */
 +	archive_entry_set_rdev(entry, (dev_t)file->rdev);
 +	archive_entry_set_size(entry, iso9660->entry_bytes_remaining);
 +	if (file->symlink.s != NULL)
 +		archive_entry_copy_symlink(entry, file->symlink.s);
 +
 +	/* Note: If the input isn't seekable, we can't rewind to
 +	 * return the same body again, so if the next entry refers to
 +	 * the same data, we have to return it as a hardlink to the
 +	 * original entry. */
 +	if (file->number != -1 &&
 +	    file->number == iso9660->previous_number) {
 +		if (iso9660->seenJoliet) {
 +			r = archive_entry_copy_hardlink_l(entry,
 +			    (const char *)iso9660->utf16be_previous_path,
 +			    iso9660->utf16be_previous_path_len,
 +			    iso9660->sconv_utf16be);
 +			if (r != 0) {
 +				if (errno == ENOMEM) {
 +					archive_set_error(&a->archive, ENOMEM,
 +					    "No 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(
 +				      iso9660->sconv_utf16be));
 +				rd_r = ARCHIVE_WARN;
 +			}
 +		} else
 +			archive_entry_set_hardlink(entry,
 +			    iso9660->previous_pathname.s);
 +		archive_entry_unset_size(entry);
 +		iso9660->entry_bytes_remaining = 0;
 +		iso9660->entry_sparse_offset = 0;
 +		return (rd_r);
 +	}
 +
 +	/* Except for the hardlink case above, if the offset of the
 +	 * next entry is before our current position, we can't seek
 +	 * backwards to extract it, so issue a warning.  Note that
 +	 * this can only happen if this entry was added to the heap
 +	 * after we passed this offset, that is, only if the directory
 +	 * mentioning this entry is later than the body of the entry.
 +	 * Such layouts are very unusual; most ISO9660 writers lay out
 +	 * and record all directory information first, then store
 +	 * all file bodies. */
 +	/* TODO: Someday, libarchive's I/O core will support optional
 +	 * seeking.  When that day comes, this code should attempt to
 +	 * seek and only return the error if the seek fails.  That
 +	 * will give us support for whacky ISO images that require
 +	 * seeking while retaining the ability to read almost all ISO
 +	 * images in a streaming fashion. */
 +	if ((file->mode & AE_IFMT) != AE_IFDIR &&
 +	    file->offset < iso9660->current_position) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Ignoring out-of-order file @%jx (%s) %jd < %jd",
 +		    (intmax_t)file->number,
 +		    iso9660->pathname.s,
 +		    (intmax_t)file->offset,
 +		    (intmax_t)iso9660->current_position);
 +		iso9660->entry_bytes_remaining = 0;
 +		iso9660->entry_sparse_offset = 0;
 +		return (ARCHIVE_WARN);
 +	}
 +
 +	/* Initialize zisofs variables. */
 +	iso9660->entry_zisofs.pz = file->pz;
 +	if (file->pz) {
 +#ifdef HAVE_ZLIB_H
 +		struct zisofs  *zisofs;
 +
 +		zisofs = &iso9660->entry_zisofs;
 +		zisofs->initialized = 0;
 +		zisofs->pz_log2_bs = file->pz_log2_bs;
 +		zisofs->pz_uncompressed_size = file->pz_uncompressed_size;
 +		zisofs->pz_offset = 0;
 +		zisofs->header_avail = 0;
 +		zisofs->header_passed = 0;
 +		zisofs->block_pointers_avail = 0;
 +#endif
 +		archive_entry_set_size(entry, file->pz_uncompressed_size);
 +	}
 +
 +	iso9660->previous_number = file->number;
 +	if (iso9660->seenJoliet) {
 +		memcpy(iso9660->utf16be_previous_path, iso9660->utf16be_path,
 +		    iso9660->utf16be_path_len);
 +		iso9660->utf16be_previous_path_len = iso9660->utf16be_path_len;
 +	} else
 +		archive_strcpy(
 +		    &iso9660->previous_pathname, iso9660->pathname.s);
 +
 +	/* Reset entry_bytes_remaining if the file is multi extent. */
 +	iso9660->entry_content = file->contents.first;
 +	if (iso9660->entry_content != NULL)
 +		iso9660->entry_bytes_remaining = iso9660->entry_content->size;
 +
 +	if (archive_entry_filetype(entry) == AE_IFDIR) {
 +		/* Overwrite nlinks by proper link number which is
 +		 * calculated from number of sub directories. */
 +		archive_entry_set_nlink(entry, 2 + file->subdirs);
 +		/* Directory data has been read completely. */
 +		iso9660->entry_bytes_remaining = 0;
 +		iso9660->entry_sparse_offset = 0;
 +	}
 +
 +	if (rd_r != ARCHIVE_OK)
 +		return (rd_r);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_read_format_iso9660_read_data_skip(struct archive_read *a)
 +{
 +	/* Because read_next_header always does an explicit skip
 +	 * to the next entry, we don't need to do anything here. */
 +	(void)a; /* UNUSED */
 +	return (ARCHIVE_OK);
 +}
 +
 +#ifdef HAVE_ZLIB_H
 +
 +static int
 +zisofs_read_data(struct archive_read *a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +	struct iso9660 *iso9660;
 +	struct zisofs  *zisofs;
 +	const unsigned char *p;
 +	size_t avail;
 +	ssize_t bytes_read;
 +	size_t uncompressed_size;
 +	int r;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +	zisofs = &iso9660->entry_zisofs;
 +
 +	p = __archive_read_ahead(a, 1, &bytes_read);
 +	if (bytes_read <= 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated zisofs file body");
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (bytes_read > iso9660->entry_bytes_remaining)
 +		bytes_read = iso9660->entry_bytes_remaining;
 +	avail = bytes_read;
 +	uncompressed_size = 0;
 +
 +	if (!zisofs->initialized) {
 +		size_t ceil, xsize;
 +
 +		/* Allocate block pointers buffer. */
 +		ceil = (zisofs->pz_uncompressed_size +
 +			(((int64_t)1) << zisofs->pz_log2_bs) - 1)
 +			>> zisofs->pz_log2_bs;
 +		xsize = (ceil + 1) * 4;
 +		if (zisofs->block_pointers_alloc < xsize) {
 +			size_t alloc;
 +
 +			if (zisofs->block_pointers != NULL)
 +				free(zisofs->block_pointers);
 +			alloc = ((xsize >> 10) + 1) << 10;
 +			zisofs->block_pointers = malloc(alloc);
 +			if (zisofs->block_pointers == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory for zisofs decompression");
 +				return (ARCHIVE_FATAL);
 +			}
 +			zisofs->block_pointers_alloc = alloc;
 +		}
 +		zisofs->block_pointers_size = xsize;
 +
 +		/* Allocate uncompressed data buffer. */
 +		xsize = 1UL << zisofs->pz_log2_bs;
 +		if (zisofs->uncompressed_buffer_size < xsize) {
 +			if (zisofs->uncompressed_buffer != NULL)
 +				free(zisofs->uncompressed_buffer);
 +			zisofs->uncompressed_buffer = malloc(xsize);
 +			if (zisofs->uncompressed_buffer == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory for zisofs decompression");
 +				return (ARCHIVE_FATAL);
 +			}
 +		}
 +		zisofs->uncompressed_buffer_size = xsize;
 +
 +		/*
 +		 * Read the file header, and check the magic code of zisofs.
 +		 */
 +		if (zisofs->header_avail < sizeof(zisofs->header)) {
 +			xsize = sizeof(zisofs->header) - zisofs->header_avail;
 +			if (avail < xsize)
 +				xsize = avail;
 +			memcpy(zisofs->header + zisofs->header_avail, p, xsize);
 +			zisofs->header_avail += xsize;
 +			avail -= xsize;
 +			p += xsize;
 +		}
 +		if (!zisofs->header_passed &&
 +		    zisofs->header_avail == sizeof(zisofs->header)) {
 +			int err = 0;
 +
 +			if (memcmp(zisofs->header, zisofs_magic,
 +			    sizeof(zisofs_magic)) != 0)
 +				err = 1;
 +			if (archive_le32dec(zisofs->header + 8)
 +			    != zisofs->pz_uncompressed_size)
 +				err = 1;
 +			if (zisofs->header[12] != 4)
 +				err = 1;
 +			if (zisofs->header[13] != zisofs->pz_log2_bs)
 +				err = 1;
 +			if (err) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_FILE_FORMAT,
 +				    "Illegal zisofs file body");
 +				return (ARCHIVE_FATAL);
 +			}
 +			zisofs->header_passed = 1;
 +		}
 +		/*
 +		 * Read block pointers.
 +		 */
 +		if (zisofs->header_passed &&
 +		    zisofs->block_pointers_avail < zisofs->block_pointers_size) {
 +			xsize = zisofs->block_pointers_size
 +			    - zisofs->block_pointers_avail;
 +			if (avail < xsize)
 +				xsize = avail;
 +			memcpy(zisofs->block_pointers
 +			    + zisofs->block_pointers_avail, p, xsize);
 +			zisofs->block_pointers_avail += xsize;
 +			avail -= xsize;
 +			p += xsize;
 +		    	if (zisofs->block_pointers_avail
 +			    == zisofs->block_pointers_size) {
 +				/* We've got all block pointers and initialize
 +				 * related variables.	*/
 +				zisofs->block_off = 0;
 +				zisofs->block_avail = 0;
 +				/* Complete a initialization */
 +				zisofs->initialized = 1;
 +			}
 +		}
 +
 +		if (!zisofs->initialized)
 +			goto next_data; /* We need more data. */
 +	}
 +
 +	/*
 +	 * Get block offsets from block pointers.
 +	 */
 +	if (zisofs->block_avail == 0) {
 +		uint32_t bst, bed;
 +
 +		if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {
 +			/* There isn't a pair of offsets. */
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Illegal zisofs block pointers");
 +			return (ARCHIVE_FATAL);
 +		}
 +		bst = archive_le32dec(
 +		    zisofs->block_pointers + zisofs->block_off);
 +		if (bst != zisofs->pz_offset + (bytes_read - avail)) {
 +			/* TODO: Should we seek offset of current file
 +			 * by bst ? */
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Illegal zisofs block pointers(cannot seek)");
 +			return (ARCHIVE_FATAL);
 +		}
 +		bed = archive_le32dec(
 +		    zisofs->block_pointers + zisofs->block_off + 4);
 +		if (bed < bst) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Illegal zisofs block pointers");
 +			return (ARCHIVE_FATAL);
 +		}
 +		zisofs->block_avail = bed - bst;
 +		zisofs->block_off += 4;
 +
 +		/* Initialize compression library for new block. */
 +		if (zisofs->stream_valid)
 +			r = inflateReset(&zisofs->stream);
 +		else
 +			r = inflateInit(&zisofs->stream);
 +		if (r != Z_OK) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Can't initialize zisofs decompression.");
 +			return (ARCHIVE_FATAL);
 +		}
 +		zisofs->stream_valid = 1;
 +		zisofs->stream.total_in = 0;
 +		zisofs->stream.total_out = 0;
 +	}
 +
 +	/*
 +	 * Make uncompressed data.
 +	 */
 +	if (zisofs->block_avail == 0) {
 +		memset(zisofs->uncompressed_buffer, 0,
 +		    zisofs->uncompressed_buffer_size);
 +		uncompressed_size = zisofs->uncompressed_buffer_size;
 +	} else {
 +		zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p;
 +		if (avail > zisofs->block_avail)
 +			zisofs->stream.avail_in = zisofs->block_avail;
 +		else
 +			zisofs->stream.avail_in = avail;
 +		zisofs->stream.next_out = zisofs->uncompressed_buffer;
 +		zisofs->stream.avail_out = zisofs->uncompressed_buffer_size;
 +
 +		r = inflate(&zisofs->stream, 0);
 +		switch (r) {
 +		case Z_OK: /* Decompressor made some progress.*/
 +		case Z_STREAM_END: /* Found end of stream. */
 +			break;
 +		default:
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "zisofs decompression failed (%d)", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		uncompressed_size =
 +		    zisofs->uncompressed_buffer_size - zisofs->stream.avail_out;
 +		avail -= zisofs->stream.next_in - p;
 +		zisofs->block_avail -= zisofs->stream.next_in - p;
 +	}
 +next_data:
 +	bytes_read -= avail;
 +	*buff = zisofs->uncompressed_buffer;
 +	*size = uncompressed_size;
 +	*offset = iso9660->entry_sparse_offset;
 +	iso9660->entry_sparse_offset += uncompressed_size;
 +	iso9660->entry_bytes_remaining -= bytes_read;
 +	iso9660->current_position += bytes_read;
 +	zisofs->pz_offset += bytes_read;
 +	iso9660->entry_bytes_unconsumed += bytes_read;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +#else /* HAVE_ZLIB_H */
 +
 +static int
 +zisofs_read_data(struct archive_read *a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +
 +	(void)buff;/* UNUSED */
 +	(void)size;/* UNUSED */
 +	(void)offset;/* UNUSED */
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +	    "zisofs is not supported on this platform.");
 +	return (ARCHIVE_FAILED);
 +}
 +
 +#endif /* HAVE_ZLIB_H */
 +
 +static int
 +archive_read_format_iso9660_read_data(struct archive_read *a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +	ssize_t bytes_read;
 +	struct iso9660 *iso9660;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +
 +	if (iso9660->entry_bytes_unconsumed) {
 +		__archive_read_consume(a, iso9660->entry_bytes_unconsumed);
 +		iso9660->entry_bytes_unconsumed = 0;
 +	}
 +
 +	if (iso9660->entry_bytes_remaining <= 0) {
 +		if (iso9660->entry_content != NULL)
 +			iso9660->entry_content = iso9660->entry_content->next;
 +		if (iso9660->entry_content == NULL) {
 +			*buff = NULL;
 +			*size = 0;
 +			*offset = iso9660->entry_sparse_offset;
 +			return (ARCHIVE_EOF);
 +		}
 +		/* Seek forward to the start of the entry. */
 +		if (iso9660->current_position < iso9660->entry_content->offset) {
 +			int64_t step;
 +
 +			step = iso9660->entry_content->offset -
 +			    iso9660->current_position;
 +			step = __archive_read_consume(a, step);
 +			if (step < 0)
 +				return ((int)step);
 +			iso9660->current_position =
 +			    iso9660->entry_content->offset;
 +		}
 +		if (iso9660->entry_content->offset < iso9660->current_position) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Ignoring out-of-order file (%s) %jd < %jd",
 +			    iso9660->pathname.s,
 +			    (intmax_t)iso9660->entry_content->offset,
 +			    (intmax_t)iso9660->current_position);
 +			*buff = NULL;
 +			*size = 0;
 +			*offset = iso9660->entry_sparse_offset;
 +			return (ARCHIVE_WARN);
 +		}
 +		iso9660->entry_bytes_remaining = iso9660->entry_content->size;
 +	}
 +	if (iso9660->entry_zisofs.pz)
 +		return (zisofs_read_data(a, buff, size, offset));
 +
 +	*buff = __archive_read_ahead(a, 1, &bytes_read);
 +	if (bytes_read == 0)
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Truncated input file");
 +	if (*buff == NULL)
 +		return (ARCHIVE_FATAL);
 +	if (bytes_read > iso9660->entry_bytes_remaining)
 +		bytes_read = iso9660->entry_bytes_remaining;
 +	*size = bytes_read;
 +	*offset = iso9660->entry_sparse_offset;
 +	iso9660->entry_sparse_offset += bytes_read;
 +	iso9660->entry_bytes_remaining -= bytes_read;
 +	iso9660->entry_bytes_unconsumed = bytes_read;
 +	iso9660->current_position += bytes_read;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_read_format_iso9660_cleanup(struct archive_read *a)
 +{
 +	struct iso9660 *iso9660;
 +	int r = ARCHIVE_OK;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +	release_files(iso9660);
 +	free(iso9660->read_ce_req.reqs);
 +	archive_string_free(&iso9660->pathname);
 +	archive_string_free(&iso9660->previous_pathname);
 +	if (iso9660->pending_files.files)
 +		free(iso9660->pending_files.files);
 +#ifdef HAVE_ZLIB_H
 +	free(iso9660->entry_zisofs.uncompressed_buffer);
 +	free(iso9660->entry_zisofs.block_pointers);
 +	if (iso9660->entry_zisofs.stream_valid) {
 +		if (inflateEnd(&iso9660->entry_zisofs.stream) != Z_OK) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Failed to clean up zlib decompressor");
 +			r = ARCHIVE_FATAL;
 +		}
 +	}
 +#endif
 +	free(iso9660->utf16be_path);
 +	free(iso9660->utf16be_previous_path);
 +	free(iso9660);
 +	(a->format->data) = NULL;
 +	return (r);
 +}
 +
 +/*
 + * This routine parses a single ISO directory record, makes sense
 + * of any extensions, and stores the result in memory.
 + */
 +static struct file_info *
 +parse_file_info(struct archive_read *a, struct file_info *parent,
 +    const unsigned char *isodirrec)
 +{
 +	struct iso9660 *iso9660;
 +	struct file_info *file;
 +	size_t name_len;
 +	const unsigned char *rr_start, *rr_end;
 +	const unsigned char *p;
 +	size_t dr_len;
 +	uint64_t fsize;
 +	int32_t location;
 +	int flags;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +
 +	dr_len = (size_t)isodirrec[DR_length_offset];
 +	name_len = (size_t)isodirrec[DR_name_len_offset];
 +	location = archive_le32dec(isodirrec + DR_extent_offset);
 +	fsize = toi(isodirrec + DR_size_offset, DR_size_size);
 +	/* Sanity check that dr_len needs at least 34. */
 +	if (dr_len < 34) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid length of directory record");
 +		return (NULL);
 +	}
 +	/* Sanity check that name_len doesn't exceed dr_len. */
 +	if (dr_len - 33 < name_len || name_len == 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid length of file identifier");
 +		return (NULL);
 +	}
 +	/* Sanity check that location doesn't exceed volume block.
 +	 * Don't check lower limit of location; it's possibility
 +	 * the location has negative value when file type is symbolic
 +	 * link or file size is zero. As far as I know latest mkisofs
 +	 * do that.
 +	 */
 +	if (location > 0 &&
 +	    (location + ((fsize + iso9660->logical_block_size -1)
 +	       / iso9660->logical_block_size)) > iso9660->volume_block) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid location of extent of file");
 +		return (NULL);
 +	}
 +	/* Sanity check that location doesn't have a negative value
 +	 * when the file is not empty. it's too large. */
 +	if (fsize != 0 && location < 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid location of extent of file");
 +		return (NULL);
 +	}
 +
 +	/* Create a new file entry and copy data from the ISO dir record. */
 +	file = (struct file_info *)calloc(1, sizeof(*file));
 +	if (file == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "No memory for file entry");
 +		return (NULL);
 +	}
 +	file->parent = parent;
 +	file->offset = iso9660->logical_block_size * (uint64_t)location;
 +	file->size = fsize;
 +	file->mtime = isodate7(isodirrec + DR_date_offset);
 +	file->ctime = file->atime = file->mtime;
 +	file->rede_files.first = NULL;
 +	file->rede_files.last = &(file->rede_files.first);
 +
 +	p = isodirrec + DR_name_offset;
 +	/* Rockridge extensions (if any) follow name.  Compute this
 +	 * before fidgeting the name_len below. */
 +	rr_start = p + name_len + (name_len & 1 ? 0 : 1);
 +	rr_end = isodirrec + dr_len;
 +
 +	if (iso9660->seenJoliet) {
 +		/* Joliet names are max 64 chars (128 bytes) according to spec,
 +		 * but genisoimage/mkisofs allows recording longer Joliet
 +		 * names which are 103 UCS2 characters(206 bytes) by their
 +		 * option '-joliet-long'.
 +		 */
 +		if (name_len > 206)
 +			name_len = 206;
 +		name_len &= ~1;
 +
 +		/* trim trailing first version and dot from filename.
 +		 *
 +		 * Remember we were in UTF-16BE land!
 +		 * SEPARATOR 1 (.) and SEPARATOR 2 (;) are both
 +		 * 16 bits big endian characters on Joliet.
 +		 *
 +		 * TODO: sanitize filename?
 +		 *       Joliet allows any UCS-2 char except:
 +		 *       *, /, :, ;, ? and \.
 +		 */
 +		/* Chop off trailing ';1' from files. */
 +		if (name_len > 4 && p[name_len-4] == 0 && p[name_len-3] == ';'
 +		    && p[name_len-2] == 0 && p[name_len-1] == '1')
 +			name_len -= 4;
 +#if 0 /* XXX: this somehow manages to strip of single-character file extensions, like '.c'. */
 +		/* Chop off trailing '.' from filenames. */
 +		if (name_len > 2 && p[name_len-2] == 0 && p[name_len-1] == '.')
 +			name_len -= 2;
 +#endif
 +		if ((file->utf16be_name = malloc(name_len)) == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "No memory for file name");
 +			return (NULL);
 +		}
 +		memcpy(file->utf16be_name, p, name_len);
 +		file->utf16be_bytes = name_len;
 +	} else {
 +		/* Chop off trailing ';1' from files. */
 +		if (name_len > 2 && p[name_len - 2] == ';' &&
 +				p[name_len - 1] == '1')
 +			name_len -= 2;
 +		/* Chop off trailing '.' from filenames. */
 +		if (name_len > 1 && p[name_len - 1] == '.')
 +			--name_len;
 +
 +		archive_strncpy(&file->name, (const char *)p, name_len);
 +	}
 +
 +	flags = isodirrec[DR_flags_offset];
 +	if (flags & 0x02)
 +		file->mode = AE_IFDIR | 0700;
 +	else
 +		file->mode = AE_IFREG | 0400;
 +	if (flags & 0x80)
 +		file->multi_extent = 1;
 +	else
 +		file->multi_extent = 0;
 +	/*
 +	 * Use a location for the file number, which is treated as an inode
 +	 * number to find out hardlink target. If Rockridge extensions is
 +	 * being used, the file number will be overwritten by FILE SERIAL
 +	 * NUMBER of RRIP "PX" extension.
 +	 * Note: Old mkisofs did not record that FILE SERIAL NUMBER
 +	 * in ISO images.
 +	 * Note2: xorriso set 0 to the location of a symlink file. 
 +	 */
 +	if (file->size == 0 && location >= 0) {
 +		/* If file->size is zero, its location points wrong place,
 +		 * and so we should not use it for the file number.
 +		 * When the location has negative value, it can be used
 +		 * for the file number.
 +		 */
 +		file->number = -1;
 +		/* Do not appear before any directory entries. */
 +		file->offset = -1;
 +	} else
 +		file->number = (int64_t)(uint32_t)location;
 +
 +	/* Rockridge extensions overwrite information from above. */
 +	if (iso9660->opt_support_rockridge) {
 +		if (parent == NULL && rr_end - rr_start >= 7) {
 +			p = rr_start;
 +			if (p[0] == 'S' && p[1] == 'P'
 +			    && p[2] == 7 && p[3] == 1
 +			    && p[4] == 0xBE && p[5] == 0xEF) {
 +				/*
 +				 * SP extension stores the suspOffset
 +				 * (Number of bytes to skip between
 +				 * filename and SUSP records.)
 +				 * It is mandatory by the SUSP standard
 +				 * (IEEE 1281).
 +				 *
 +				 * It allows SUSP to coexist with
 +				 * non-SUSP uses of the System
 +				 * Use Area by placing non-SUSP data
 +				 * before SUSP data.
 +				 *
 +				 * SP extension must be in the root
 +				 * directory entry, disable all SUSP
 +				 * processing if not found.
 +				 */
 +				iso9660->suspOffset = p[6];
 +				iso9660->seenSUSP = 1;
 +				rr_start += 7;
 +			}
 +		}
 +		if (iso9660->seenSUSP) {
 +			int r;
 +
 +			file->name_continues = 0;
 +			file->symlink_continues = 0;
 +			rr_start += iso9660->suspOffset;
 +			r = parse_rockridge(a, file, rr_start, rr_end);
 +			if (r != ARCHIVE_OK) {
 +				free(file);
 +				return (NULL);
 +			}
 +		} else
 +			/* If there isn't SUSP, disable parsing
 +			 * rock ridge extensions. */
 +			iso9660->opt_support_rockridge = 0;
 +	}
 +
 +	file->nlinks = 1;/* Reset nlink. we'll calculate it later. */
 +	/* Tell file's parent how many children that parent has. */
 +	if (parent != NULL && (flags & 0x02))
 +		parent->subdirs++;
 +
 +	if (iso9660->seenRockridge) {
 +		if (parent != NULL && parent->parent == NULL &&
 +		    (flags & 0x02) && iso9660->rr_moved == NULL &&
 +		    (strcmp(file->name.s, "rr_moved") == 0 ||
 +		     strcmp(file->name.s, ".rr_moved") == 0)) {
 +			iso9660->rr_moved = file;
 +			file->rr_moved = 1;
 +			file->rr_moved_has_re_only = 1;
 +			file->re = 0;
 +			parent->subdirs--;
 +		} else if (file->re) {
 +			/*
 +			 * Sanity check: file's parent is rr_moved.
 +			 */
 +			if (parent == NULL || parent->rr_moved == 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge RE");
 +				return (NULL);
 +			}
 +			/*
 +			 * Sanity check: file does not have "CL" extension.
 +			 */
 +			if (file->cl_offset) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge RE and CL");
 +				return (NULL);
 +			}
 +			/*
 +			 * Sanity check: The file type must be a directory.
 +			 */
 +			if ((flags & 0x02) == 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge RE");
 +				return (NULL);
 +			}
 +		} else if (parent != NULL && parent->rr_moved)
 +			file->rr_moved_has_re_only = 0;
 +		else if (parent != NULL && (flags & 0x02) &&
 +		    (parent->re || parent->re_descendant))
 +			file->re_descendant = 1;
 +		if (file->cl_offset) {
- 			struct file_info *p;
++			struct file_info *r;
 +
 +			if (parent == NULL || parent->parent == NULL) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge CL");
 +				return (NULL);
 +			}
 +			/*
 +			 * Sanity check: The file type must be a regular file.
 +			 */
 +			if ((flags & 0x02) != 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge CL");
 +				return (NULL);
 +			}
 +			parent->subdirs++;
 +			/* Overwrite an offset and a number of this "CL" entry
 +			 * to appear before other dirs. "+1" to those is to
 +			 * make sure to appear after "RE" entry which this
 +			 * "CL" entry should be connected with. */
 +			file->offset = file->number = file->cl_offset + 1;
 +
 +			/*
 +			 * Sanity check: cl_offset does not point at its
 +			 * the parents or itself.
 +			 */
- 			for (p = parent; p; p = p->parent) {
- 				if (p->offset == file->cl_offset) {
++			for (r = parent; r; r = r->parent) {
++				if (r->offset == file->cl_offset) {
 +					archive_set_error(&a->archive,
 +					    ARCHIVE_ERRNO_MISC,
 +					    "Invalid Rockridge CL");
 +					return (NULL);
 +				}
 +			}
 +			if (file->cl_offset == file->offset ||
 +			    parent->rr_moved) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge CL");
 +				return (NULL);
 +			}
 +		}
 +	}
 +
 +#if DEBUG
 +	/* DEBUGGING: Warn about attributes I don't yet fully support. */
 +	if ((flags & ~0x02) != 0) {
 +		fprintf(stderr, "\n ** Unrecognized flag: ");
 +		dump_isodirrec(stderr, isodirrec);
 +		fprintf(stderr, "\n");
 +	} else if (toi(isodirrec + DR_volume_sequence_number_offset, 2) != 1) {
 +		fprintf(stderr, "\n ** Unrecognized sequence number: ");
 +		dump_isodirrec(stderr, isodirrec);
 +		fprintf(stderr, "\n");
 +	} else if (*(isodirrec + DR_file_unit_size_offset) != 0) {
 +		fprintf(stderr, "\n ** Unexpected file unit size: ");
 +		dump_isodirrec(stderr, isodirrec);
 +		fprintf(stderr, "\n");
 +	} else if (*(isodirrec + DR_interleave_offset) != 0) {
 +		fprintf(stderr, "\n ** Unexpected interleave: ");
 +		dump_isodirrec(stderr, isodirrec);
 +		fprintf(stderr, "\n");
 +	} else if (*(isodirrec + DR_ext_attr_length_offset) != 0) {
 +		fprintf(stderr, "\n ** Unexpected extended attribute length: ");
 +		dump_isodirrec(stderr, isodirrec);
 +		fprintf(stderr, "\n");
 +	}
 +#endif
 +	register_file(iso9660, file);
 +	return (file);
 +}
 +
 +static int
 +parse_rockridge(struct archive_read *a, struct file_info *file,
 +    const unsigned char *p, const unsigned char *end)
 +{
 +	struct iso9660 *iso9660;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +
 +	while (p + 4 <= end  /* Enough space for another entry. */
 +	    && p[0] >= 'A' && p[0] <= 'Z' /* Sanity-check 1st char of name. */
 +	    && p[1] >= 'A' && p[1] <= 'Z' /* Sanity-check 2nd char of name. */
 +	    && p[2] >= 4 /* Sanity-check length. */
 +	    && p + p[2] <= end) { /* Sanity-check length. */
 +		const unsigned char *data = p + 4;
 +		int data_length = p[2] - 4;
 +		int version = p[3];
 +
 +		/*
 +		 * Yes, each 'if' here does test p[0] again.
 +		 * Otherwise, the fall-through handling to catch
 +		 * unsupported extensions doesn't work.
 +		 */
 +		switch(p[0]) {
 +		case 'C':
 +			if (p[0] == 'C' && p[1] == 'E') {
 +				if (version == 1 && data_length == 24) {
 +					/*
 +					 * CE extension comprises:
 +					 *   8 byte sector containing extension
 +					 *   8 byte offset w/in above sector
 +					 *   8 byte length of continuation
 +					 */
 +					int32_t location =
 +					    archive_le32dec(data);
 +					file->ce_offset =
 +					    archive_le32dec(data+8);
 +					file->ce_size =
 +					    archive_le32dec(data+16);
 +					if (register_CE(a, location, file)
 +					    != ARCHIVE_OK)
 +						return (ARCHIVE_FATAL);
 +				}
 +				break;
 +			}
 +			if (p[0] == 'C' && p[1] == 'L') {
 +				if (version == 1 && data_length == 8) {
 +					file->cl_offset = (uint64_t)
 +					    iso9660->logical_block_size *
 +					    (uint64_t)archive_le32dec(data);
 +					iso9660->seenRockridge = 1;
 +				}
 +				break;
 +			}
 +			/* FALLTHROUGH */
 +		case 'N':
 +			if (p[0] == 'N' && p[1] == 'M') {
 +				if (version == 1) {
 +					parse_rockridge_NM1(file,
 +					    data, data_length);
 +					iso9660->seenRockridge = 1;
 +				}
 +				break;
 +			}
 +			/* FALLTHROUGH */
 +		case 'P':
 +			if (p[0] == 'P' && p[1] == 'D') {
 +				/*
 +				 * PD extension is padding;
 +				 * contents are always ignored.
 +				 */
 +				break;
 +			}
 +			if (p[0] == 'P' && p[1] == 'L') {
 +				/*
 +				 * PL extension won't appear;
 +				 * contents are always ignored.
 +				 */
 +				break;
 +			}
 +			if (p[0] == 'P' && p[1] == 'N') {
 +				if (version == 1 && data_length == 16) {
 +					file->rdev = toi(data,4);
 +					file->rdev <<= 32;
 +					file->rdev |= toi(data + 8, 4);
 +					iso9660->seenRockridge = 1;
 +				}
 +				break;
 +			}
 +			if (p[0] == 'P' && p[1] == 'X') {
 +				/*
 +				 * PX extension comprises:
 +				 *   8 bytes for mode,
 +				 *   8 bytes for nlinks,
 +				 *   8 bytes for uid,
 +				 *   8 bytes for gid,
 +				 *   8 bytes for inode.
 +				 */
 +				if (version == 1) {
 +					if (data_length >= 8)
 +						file->mode
 +						    = toi(data, 4);
 +					if (data_length >= 16)
 +						file->nlinks
 +						    = toi(data + 8, 4);
 +					if (data_length >= 24)
 +						file->uid
 +						    = toi(data + 16, 4);
 +					if (data_length >= 32)
 +						file->gid
 +						    = toi(data + 24, 4);
 +					if (data_length >= 40)
 +						file->number
 +						    = toi(data + 32, 4);
 +					iso9660->seenRockridge = 1;
 +				}
 +				break;
 +			}
 +			/* FALLTHROUGH */
 +		case 'R':
 +			if (p[0] == 'R' && p[1] == 'E' && version == 1) {
 +				file->re = 1;
 +				iso9660->seenRockridge = 1;
 +				break;
 +			}
 +			if (p[0] == 'R' && p[1] == 'R' && version == 1) {
 +				/*
 +				 * RR extension comprises:
 +				 *    one byte flag value
 +				 * This extension is obsolete,
 +				 * so contents are always ignored.
 +				 */
 +				break;
 +			}
 +			/* FALLTHROUGH */
 +		case 'S':
 +			if (p[0] == 'S' && p[1] == 'L') {
 +				if (version == 1) {
 +					parse_rockridge_SL1(file,
 +					    data, data_length);
 +					iso9660->seenRockridge = 1;
 +				}
 +				break;
 +			}
 +			if (p[0] == 'S' && p[1] == 'T'
 +			    && data_length == 0 && version == 1) {
 +				/*
 +				 * ST extension marks end of this
 +				 * block of SUSP entries.
 +				 *
 +				 * It allows SUSP to coexist with
 +				 * non-SUSP uses of the System
 +				 * Use Area by placing non-SUSP data
 +				 * after SUSP data.
 +				 */
 +				iso9660->seenSUSP = 0;
 +				iso9660->seenRockridge = 0;
 +				return (ARCHIVE_OK);
 +			}
 +		case 'T':
 +			if (p[0] == 'T' && p[1] == 'F') {
 +				if (version == 1) {
 +					parse_rockridge_TF1(file,
 +					    data, data_length);
 +					iso9660->seenRockridge = 1;
 +				}
 +				break;
 +			}
 +			/* FALLTHROUGH */
 +		case 'Z':
 +			if (p[0] == 'Z' && p[1] == 'F') {
 +				if (version == 1)
 +					parse_rockridge_ZF1(file,
 +					    data, data_length);
 +				break;
 +			}
 +			/* FALLTHROUGH */
 +		default:
 +			/* The FALLTHROUGHs above leave us here for
 +			 * any unsupported extension. */
 +			break;
 +		}
 +
 +
 +
 +		p += p[2];
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +register_CE(struct archive_read *a, int32_t location,
 +    struct file_info *file)
 +{
 +	struct iso9660 *iso9660;
 +	struct read_ce_queue *heap;
 +	struct read_ce_req *p;
 +	uint64_t offset, parent_offset;
 +	int hole, parent;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +	offset = ((uint64_t)location) * (uint64_t)iso9660->logical_block_size;
 +	if (((file->mode & AE_IFMT) == AE_IFREG &&
 +	    offset >= file->offset) ||
 +	    offset < iso9660->current_position ||
 +	    (((uint64_t)file->ce_offset) + file->ce_size)
 +	      > iso9660->logical_block_size ||
 +	    offset + file->ce_offset + file->ce_size
 +		  > iso9660->volume_size) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid parameter in SUSP \"CE\" extension");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Expand our CE list as necessary. */
 +	heap = &(iso9660->read_ce_req);
 +	if (heap->cnt >= heap->allocated) {
 +		int new_size;
 +
 +		if (heap->allocated < 16)
 +			new_size = 16;
 +		else
 +			new_size = heap->allocated * 2;
 +		/* Overflow might keep us from growing the list. */
 +		if (new_size <= heap->allocated) {
 +			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		p = malloc(new_size * sizeof(p[0]));
 +		if (p == NULL) {
 +			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (heap->reqs != NULL) {
 +			memcpy(p, heap->reqs, heap->cnt * sizeof(*p));
 +			free(heap->reqs);
 +		}
 +		heap->reqs = p;
 +		heap->allocated = new_size;
 +	}
 +
 +	/*
 +	 * Start with hole at end, walk it up tree to find insertion point.
 +	 */
 +	hole = heap->cnt++;
 +	while (hole > 0) {
 +		parent = (hole - 1)/2;
 +		parent_offset = heap->reqs[parent].offset;
 +		if (offset >= parent_offset) {
 +			heap->reqs[hole].offset = offset;
 +			heap->reqs[hole].file = file;
 +			return (ARCHIVE_OK);
 +		}
 +		/* Move parent into hole <==> move hole up tree. */
 +		heap->reqs[hole] = heap->reqs[parent];
 +		hole = parent;
 +	}
 +	heap->reqs[0].offset = offset;
 +	heap->reqs[0].file = file;
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +next_CE(struct read_ce_queue *heap)
 +{
 +	uint64_t a_offset, b_offset, c_offset;
 +	int a, b, c;
 +	struct read_ce_req tmp;
 +
 +	if (heap->cnt < 1)
 +		return;
 +
 +	/*
 +	 * Move the last item in the heap to the root of the tree
 +	 */
 +	heap->reqs[0] = heap->reqs[--(heap->cnt)];
 +
 +	/*
 +	 * Rebalance the heap.
 +	 */
 +	a = 0; /* Starting element and its offset */
 +	a_offset = heap->reqs[a].offset;
 +	for (;;) {
 +		b = a + a + 1; /* First child */
 +		if (b >= heap->cnt)
 +			return;
 +		b_offset = heap->reqs[b].offset;
 +		c = b + 1; /* Use second child if it is smaller. */
 +		if (c < heap->cnt) {
 +			c_offset = heap->reqs[c].offset;
 +			if (c_offset < b_offset) {
 +				b = c;
 +				b_offset = c_offset;
 +			}
 +		}
 +		if (a_offset <= b_offset)
 +			return;
 +		tmp = heap->reqs[a];
 +		heap->reqs[a] = heap->reqs[b];
 +		heap->reqs[b] = tmp;
 +		a = b;
 +	}
 +}
 +
 +
 +static int
 +read_CE(struct archive_read *a, struct iso9660 *iso9660)
 +{
 +	struct read_ce_queue *heap;
 +	const unsigned char *b, *p, *end;
 +	struct file_info *file;
 +	size_t step;
 +	int r;
 +
 +	/* Read data which RRIP "CE" extension points. */
 +	heap = &(iso9660->read_ce_req);
 +	step = iso9660->logical_block_size;
 +	while (heap->cnt &&
 +	    heap->reqs[0].offset == iso9660->current_position) {
 +		b = __archive_read_ahead(a, step, NULL);
 +		if (b == NULL) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Failed to read full block when scanning "
 +			    "ISO9660 directory list");
 +			return (ARCHIVE_FATAL);
 +		}
 +		do {
 +			file = heap->reqs[0].file;
 +			if (file->ce_offset + file->ce_size > step) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_FILE_FORMAT,
 +				    "Malformed CE information");
 +				return (ARCHIVE_FATAL);
 +			}
 +			p = b + file->ce_offset;
 +			end = p + file->ce_size;
 +			next_CE(heap);
 +			r = parse_rockridge(a, file, p, end);
 +			if (r != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		} while (heap->cnt &&
 +		    heap->reqs[0].offset == iso9660->current_position);
 +		/* NOTE: Do not move this consume's code to fron of
 +		 * do-while loop. Registration of nested CE extension
 +		 * might cause error because of current position. */
 +		__archive_read_consume(a, step);
 +		iso9660->current_position += step;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +parse_rockridge_NM1(struct file_info *file,
 +		    const unsigned char *data, int data_length)
 +{
 +	if (!file->name_continues)
 +		archive_string_empty(&file->name);
 +	file->name_continues = 0;
 +	if (data_length < 1)
 +		return;
 +	/*
 +	 * NM version 1 extension comprises:
 +	 *   1 byte flag, value is one of:
 +	 *     = 0: remainder is name
 +	 *     = 1: remainder is name, next NM entry continues name
 +	 *     = 2: "."
 +	 *     = 4: ".."
 +	 *     = 32: Implementation specific
 +	 *     All other values are reserved.
 +	 */
 +	switch(data[0]) {
 +	case 0:
 +		if (data_length < 2)
 +			return;
 +		archive_strncat(&file->name,
 +		    (const char *)data + 1, data_length - 1);
 +		break;
 +	case 1:
 +		if (data_length < 2)
 +			return;
 +		archive_strncat(&file->name,
 +		    (const char *)data + 1, data_length - 1);
 +		file->name_continues = 1;
 +		break;
 +	case 2:
 +		archive_strcat(&file->name, ".");
 +		break;
 +	case 4:
 +		archive_strcat(&file->name, "..");
 +		break;
 +	default:
 +		return;
 +	}
 +
 +}
 +
 +static void
 +parse_rockridge_TF1(struct file_info *file, const unsigned char *data,
 +    int data_length)
 +{
 +	char flag;
 +	/*
 +	 * TF extension comprises:
 +	 *   one byte flag
 +	 *   create time (optional)
 +	 *   modify time (optional)
 +	 *   access time (optional)
 +	 *   attribute time (optional)
 +	 *  Time format and presence of fields
 +	 *  is controlled by flag bits.
 +	 */
 +	if (data_length < 1)
 +		return;
 +	flag = data[0];
 +	++data;
 +	--data_length;
 +	if (flag & 0x80) {
 +		/* Use 17-byte time format. */
 +		if ((flag & 1) && data_length >= 17) {
 +			/* Create time. */
 +			file->birthtime_is_set = 1;
 +			file->birthtime = isodate17(data);
 +			data += 17;
 +			data_length -= 17;
 +		}
 +		if ((flag & 2) && data_length >= 17) {
 +			/* Modify time. */
 +			file->mtime = isodate17(data);
 +			data += 17;
 +			data_length -= 17;
 +		}
 +		if ((flag & 4) && data_length >= 17) {
 +			/* Access time. */
 +			file->atime = isodate17(data);
 +			data += 17;
 +			data_length -= 17;
 +		}
 +		if ((flag & 8) && data_length >= 17) {
 +			/* Attribute change time. */
 +			file->ctime = isodate17(data);
 +		}
 +	} else {
 +		/* Use 7-byte time format. */
 +		if ((flag & 1) && data_length >= 7) {
 +			/* Create time. */
 +			file->birthtime_is_set = 1;
 +			file->birthtime = isodate7(data);
 +			data += 7;
 +			data_length -= 7;
 +		}
 +		if ((flag & 2) && data_length >= 7) {
 +			/* Modify time. */
 +			file->mtime = isodate7(data);
 +			data += 7;
 +			data_length -= 7;
 +		}
 +		if ((flag & 4) && data_length >= 7) {
 +			/* Access time. */
 +			file->atime = isodate7(data);
 +			data += 7;
 +			data_length -= 7;
 +		}
 +		if ((flag & 8) && data_length >= 7) {
 +			/* Attribute change time. */
 +			file->ctime = isodate7(data);
 +		}
 +	}
 +}
 +
 +static void
 +parse_rockridge_SL1(struct file_info *file, const unsigned char *data,
 +    int data_length)
 +{
 +	const char *separator = "";
 +
 +	if (!file->symlink_continues || file->symlink.length < 1)
 +		archive_string_empty(&file->symlink);
 +	else if (!file->symlink_continues &&
 +	    file->symlink.s[file->symlink.length - 1] != '/')
 +		separator = "/";
 +	file->symlink_continues = 0;
 +
 +	/*
 +	 * Defined flag values:
 +	 *  0: This is the last SL record for this symbolic link
 +	 *  1: this symbolic link field continues in next SL entry
 +	 *  All other values are reserved.
 +	 */
 +	if (data_length < 1)
 +		return;
 +	switch(*data) {
 +	case 0:
 +		break;
 +	case 1:
 +		file->symlink_continues = 1;
 +		break;
 +	default:
 +		return;
 +	}
 +	++data;  /* Skip flag byte. */
 +	--data_length;
 +
 +	/*
 +	 * SL extension body stores "components".
 +	 * Basically, this is a complicated way of storing
 +	 * a POSIX path.  It also interferes with using
 +	 * symlinks for storing non-path data. <sigh>
 +	 *
 +	 * Each component is 2 bytes (flag and length)
 +	 * possibly followed by name data.
 +	 */
 +	while (data_length >= 2) {
 +		unsigned char flag = *data++;
 +		unsigned char nlen = *data++;
 +		data_length -= 2;
 +
 +		archive_strcat(&file->symlink, separator);
 +		separator = "/";
 +
 +		switch(flag) {
 +		case 0: /* Usual case, this is text. */
 +			if (data_length < nlen)
 +				return;
 +			archive_strncat(&file->symlink,
 +			    (const char *)data, nlen);
 +			break;
 +		case 0x01: /* Text continues in next component. */
 +			if (data_length < nlen)
 +				return;
 +			archive_strncat(&file->symlink,
 +			    (const char *)data, nlen);
 +			separator = "";
 +			break;
 +		case 0x02: /* Current dir. */
 +			archive_strcat(&file->symlink, ".");
 +			break;
 +		case 0x04: /* Parent dir. */
 +			archive_strcat(&file->symlink, "..");
 +			break;
 +		case 0x08: /* Root of filesystem. */
 +			archive_strcat(&file->symlink, "/");
 +			separator = "";
 +			break;
 +		case 0x10: /* Undefined (historically "volume root" */
 +			archive_string_empty(&file->symlink);
 +			archive_strcat(&file->symlink, "ROOT");
 +			break;
 +		case 0x20: /* Undefined (historically "hostname") */
 +			archive_strcat(&file->symlink, "hostname");
 +			break;
 +		default:
 +			/* TODO: issue a warning ? */
 +			return;
 +		}
 +		data += nlen;
 +		data_length -= nlen;
 +	}
 +}
 +
 +static void
 +parse_rockridge_ZF1(struct file_info *file, const unsigned char *data,
 +    int data_length)
 +{
 +
 +	if (data[0] == 0x70 && data[1] == 0x7a && data_length == 12) {
 +		/* paged zlib */
 +		file->pz = 1;
 +		file->pz_log2_bs = data[3];
 +		file->pz_uncompressed_size = archive_le32dec(&data[4]);
 +	}
 +}
 +
 +static void
 +register_file(struct iso9660 *iso9660, struct file_info *file)
 +{
 +
 +	file->use_next = iso9660->use_files;
 +	iso9660->use_files = file;
 +}
 +
 +static void
 +release_files(struct iso9660 *iso9660)
 +{
 +	struct content *con, *connext;
 +	struct file_info *file;
 +
 +	file = iso9660->use_files;
 +	while (file != NULL) {
 +		struct file_info *next = file->use_next;
 +
 +		archive_string_free(&file->name);
 +		archive_string_free(&file->symlink);
 +		free(file->utf16be_name);
 +		con = file->contents.first;
 +		while (con != NULL) {
 +			connext = con->next;
 +			free(con);
 +			con = connext;
 +		}
 +		free(file);
 +		file = next;
 +	}
 +}
 +
 +static int
 +next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
 +    struct file_info **pfile)
 +{
 +	struct file_info *file;
 +	int r;
 +
 +	r = next_cache_entry(a, iso9660, pfile);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	file = *pfile;
 +
 +	/* Don't waste time seeking for zero-length bodies. */
 +	if (file->size == 0)
 +		file->offset = iso9660->current_position;
 +
 +	/* flush any remaining bytes from the last round to ensure
 +	 * we're positioned */
 +	if (iso9660->entry_bytes_unconsumed) {
 +		__archive_read_consume(a, iso9660->entry_bytes_unconsumed);
 +		iso9660->entry_bytes_unconsumed = 0;
 +	}
 +
 +	/* Seek forward to the start of the entry. */
 +	if (iso9660->current_position < file->offset) {
 +		int64_t step;
 +
 +		step = file->offset - iso9660->current_position;
 +		step = __archive_read_consume(a, step);
 +		if (step < 0)
 +			return ((int)step);
 +		iso9660->current_position = file->offset;
 +	}
 +
 +	/* We found body of file; handle it now. */
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +next_cache_entry(struct archive_read *a, struct iso9660 *iso9660,
 +    struct file_info **pfile)
 +{
 +	struct file_info *file;
 +	struct {
 +		struct file_info	*first;
 +		struct file_info	**last;
 +	}	empty_files;
 +	int64_t number;
 +	int count;
 +
 +	file = cache_get_entry(iso9660);
 +	if (file != NULL) {
 +		*pfile = file;
 +		return (ARCHIVE_OK);
 +	}
 +
 +	for (;;) {
 +		struct file_info *re, *d;
 +
 +		*pfile = file = next_entry(iso9660);
 +		if (file == NULL) {
 +			/*
 +			 * If directory entries all which are descendant of
 +			 * rr_moved are stil remaning, expose their. 
 +			 */
 +			if (iso9660->re_files.first != NULL && 
 +			    iso9660->rr_moved != NULL &&
 +			    iso9660->rr_moved->rr_moved_has_re_only)
 +				/* Expose "rr_moved" entry. */
 +				cache_add_entry(iso9660, iso9660->rr_moved);
 +			while ((re = re_get_entry(iso9660)) != NULL) {
 +				/* Expose its descendant dirs. */
 +				while ((d = rede_get_entry(re)) != NULL)
 +					cache_add_entry(iso9660, d);
 +			}
 +			if (iso9660->cache_files.first != NULL)
 +				return (next_cache_entry(a, iso9660, pfile));
 +			return (ARCHIVE_EOF);
 +		}
 +
 +		if (file->cl_offset) {
 +			struct file_info *first_re = NULL;
 +			int nexted_re = 0;
 +
 +			/*
 +			 * Find "RE" dir for the current file, which
 +			 * has "CL" flag.
 +			 */
 +			while ((re = re_get_entry(iso9660))
 +			    != first_re) {
 +				if (first_re == NULL)
 +					first_re = re;
 +				if (re->offset == file->cl_offset) {
 +					re->parent->subdirs--;
 +					re->parent = file->parent;
 +					re->re = 0;
 +					if (re->parent->re_descendant) {
 +						nexted_re = 1;
 +						re->re_descendant = 1;
 +						if (rede_add_entry(re) < 0)
 +							goto fatal_rr;
 +						/* Move a list of descendants
 +						 * to a new ancestor. */
 +						while ((d = rede_get_entry(
 +						    re)) != NULL)
 +							if (rede_add_entry(d)
 +							    < 0)
 +								goto fatal_rr;
 +						break;
 +					}
 +					/* Replace the current file
 +					 * with "RE" dir */
 +					*pfile = file = re;
 +					/* Expose its descendant */
 +					while ((d = rede_get_entry(
 +					    file)) != NULL)
 +						cache_add_entry(
 +						    iso9660, d);
 +					break;
 +				} else
 +					re_add_entry(iso9660, re);
 +			}
 +			if (nexted_re) {
 +				/*
 +				 * Do not expose this at this time
 +				 * because we have not gotten its full-path
 +				 * name yet.
 +				 */
 +				continue;
 +			}
 +		} else if ((file->mode & AE_IFMT) == AE_IFDIR) {
 +			int r;
 +
 +			/* Read file entries in this dir. */
 +			r = read_children(a, file);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +
 +			/*
 +			 * Handle a special dir of Rockridge extensions,
 +			 * "rr_moved".
 +			 */
 +			if (file->rr_moved) {
 +				/*
 +				 * If this has only the subdirectories which
 +				 * have "RE" flags, do not expose at this time.
 +				 */
 +				if (file->rr_moved_has_re_only)
 +					continue;
 +				/* Otherwise expose "rr_moved" entry. */
 +			} else if (file->re) {
 +				/*
 +				 * Do not expose this at this time
 +				 * because we have not gotten its full-path
 +				 * name yet.
 +				 */
 +				re_add_entry(iso9660, file);
 +				continue;
 +			} else if (file->re_descendant) {
 +				/*
 +				 * If the top level "RE" entry of this entry
 +				 * is not exposed, we, accordingly, should not
 +				 * expose this entry at this time because
 +				 * we cannot make its proper full-path name.
 +				 */
 +				if (rede_add_entry(file) == 0)
 +					continue;
 +				/* Otherwise we can expose this entry because
 +				 * it seems its top level "RE" has already been
 +				 * exposed. */
 +			}
 +		}
 +		break;
 +	}
 +
 +	if ((file->mode & AE_IFMT) != AE_IFREG || file->number == -1)
 +		return (ARCHIVE_OK);
 +
 +	count = 0;
 +	number = file->number;
 +	iso9660->cache_files.first = NULL;
 +	iso9660->cache_files.last = &(iso9660->cache_files.first);
 +	empty_files.first = NULL;
 +	empty_files.last = &empty_files.first;
 +	/* Collect files which has the same file serial number.
 +	 * Peek pending_files so that file which number is different
 +	 * is not put bak. */
 +	while (iso9660->pending_files.used > 0 &&
 +	    (iso9660->pending_files.files[0]->number == -1 ||
 +	     iso9660->pending_files.files[0]->number == number)) {
 +		if (file->number == -1) {
 +			/* This file has the same offset
 +			 * but it's wrong offset which empty files
 +			 * and symlink files have.
 +			 * NOTE: This wrong offse was recorded by
 +			 * old mkisofs utility. If ISO images is
 +			 * created by latest mkisofs, this does not
 +			 * happen.
 +			 */
 +			file->next = NULL;
 +			*empty_files.last = file;
 +			empty_files.last = &(file->next);
 +		} else {
 +			count++;
 +			cache_add_entry(iso9660, file);
 +		}
 +		file = next_entry(iso9660);
 +	}
 +
 +	if (count == 0) {
 +		*pfile = file;
 +		return ((file == NULL)?ARCHIVE_EOF:ARCHIVE_OK);
 +	}
 +	if (file->number == -1) {
 +		file->next = NULL;
 +		*empty_files.last = file;
 +		empty_files.last = &(file->next);
 +	} else {
 +		count++;
 +		cache_add_entry(iso9660, file);
 +	}
 +
 +	if (count > 1) {
 +		/* The count is the same as number of hardlink,
 +		 * so much so that each nlinks of files in cache_file
 +		 * is overwritten by value of the count.
 +		 */
 +		for (file = iso9660->cache_files.first;
 +		    file != NULL; file = file->next)
 +			file->nlinks = count;
 +	}
 +	/* If there are empty files, that files are added
 +	 * to the tail of the cache_files. */
 +	if (empty_files.first != NULL) {
 +		*iso9660->cache_files.last = empty_files.first;
 +		iso9660->cache_files.last = empty_files.last;
 +	}
 +	*pfile = cache_get_entry(iso9660);
 +	return ((*pfile == NULL)?ARCHIVE_EOF:ARCHIVE_OK);
 +
 +fatal_rr:
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +	    "Failed to connect 'CL' pointer to 'RE' rr_moved pointer of"
 +	    "Rockridge extensions");
 +	return (ARCHIVE_FATAL);
 +}
 +
 +static inline void
 +re_add_entry(struct iso9660 *iso9660, struct file_info *file)
 +{
 +	file->re_next = NULL;
 +	*iso9660->re_files.last = file;
 +	iso9660->re_files.last = &(file->re_next);
 +}
 +
 +static inline struct file_info *
 +re_get_entry(struct iso9660 *iso9660)
 +{
 +	struct file_info *file;
 +
 +	if ((file = iso9660->re_files.first) != NULL) {
 +		iso9660->re_files.first = file->re_next;
 +		if (iso9660->re_files.first == NULL)
 +			iso9660->re_files.last =
 +			    &(iso9660->re_files.first);
 +	}
 +	return (file);
 +}
 +
 +static inline int
 +rede_add_entry(struct file_info *file)
 +{
 +	struct file_info *re;
 +
 +	/*
 +	 * Find "RE" entry.
 +	 */
 +	re = file->parent;
 +	while (re != NULL && !re->re)
 +		re = re->parent;
 +	if (re == NULL)
 +		return (-1);
 +
 +	file->re_next = NULL;
 +	*re->rede_files.last = file;
 +	re->rede_files.last = &(file->re_next);
 +	return (0);
 +}
 +
 +static inline struct file_info *
 +rede_get_entry(struct file_info *re)
 +{
 +	struct file_info *file;
 +
 +	if ((file = re->rede_files.first) != NULL) {
 +		re->rede_files.first = file->re_next;
 +		if (re->rede_files.first == NULL)
 +			re->rede_files.last =
 +			    &(re->rede_files.first);
 +	}
 +	return (file);
 +}
 +
 +static inline void
 +cache_add_entry(struct iso9660 *iso9660, struct file_info *file)
 +{
 +	file->next = NULL;
 +	*iso9660->cache_files.last = file;
 +	iso9660->cache_files.last = &(file->next);
 +}
 +
 +static inline struct file_info *
 +cache_get_entry(struct iso9660 *iso9660)
 +{
 +	struct file_info *file;
 +
 +	if ((file = iso9660->cache_files.first) != NULL) {
 +		iso9660->cache_files.first = file->next;
 +		if (iso9660->cache_files.first == NULL)
 +			iso9660->cache_files.last =
 +			    &(iso9660->cache_files.first);
 +	}
 +	return (file);
 +}
 +
 +static int
 +heap_add_entry(struct archive_read *a, struct heap_queue *heap,
 +    struct file_info *file, uint64_t key)
 +{
 +	uint64_t file_key, parent_key;
 +	int hole, parent;
 +
 +	/* Expand our pending files list as necessary. */
 +	if (heap->used >= heap->allocated) {
 +		struct file_info **new_pending_files;
 +		int new_size = heap->allocated * 2;
 +
 +		if (heap->allocated < 1024)
 +			new_size = 1024;
 +		/* Overflow might keep us from growing the list. */
 +		if (new_size <= heap->allocated) {
 +			archive_set_error(&a->archive,
 +			    ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		new_pending_files = (struct file_info **)
 +		    malloc(new_size * sizeof(new_pending_files[0]));
 +		if (new_pending_files == NULL) {
 +			archive_set_error(&a->archive,
 +			    ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		memcpy(new_pending_files, heap->files,
 +		    heap->allocated * sizeof(new_pending_files[0]));
 +		if (heap->files != NULL)
 +			free(heap->files);
 +		heap->files = new_pending_files;
 +		heap->allocated = new_size;
 +	}
 +
 +	file_key = file->key = key;
 +
 +	/*
 +	 * Start with hole at end, walk it up tree to find insertion point.
 +	 */
 +	hole = heap->used++;
 +	while (hole > 0) {
 +		parent = (hole - 1)/2;
 +		parent_key = heap->files[parent]->key;
 +		if (file_key >= parent_key) {
 +			heap->files[hole] = file;
 +			return (ARCHIVE_OK);
 +		}
 +		/* Move parent into hole <==> move hole up tree. */
 +		heap->files[hole] = heap->files[parent];
 +		hole = parent;
 +	}
 +	heap->files[0] = file;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static struct file_info *
 +heap_get_entry(struct heap_queue *heap)
 +{
 +	uint64_t a_key, b_key, c_key;
 +	int a, b, c;
 +	struct file_info *r, *tmp;
 +
 +	if (heap->used < 1)
 +		return (NULL);
 +
 +	/*
 +	 * The first file in the list is the earliest; we'll return this.
 +	 */
 +	r = heap->files[0];
 +
 +	/*
 +	 * Move the last item in the heap to the root of the tree
 +	 */
 +	heap->files[0] = heap->files[--(heap->used)];
 +
 +	/*
 +	 * Rebalance the heap.
 +	 */
 +	a = 0; /* Starting element and its heap key */
 +	a_key = heap->files[a]->key;
 +	for (;;) {
 +		b = a + a + 1; /* First child */
 +		if (b >= heap->used)
 +			return (r);
 +		b_key = heap->files[b]->key;
 +		c = b + 1; /* Use second child if it is smaller. */
 +		if (c < heap->used) {
 +			c_key = heap->files[c]->key;
 +			if (c_key < b_key) {
 +				b = c;
 +				b_key = c_key;
 +			}
 +		}
 +		if (a_key <= b_key)
 +			return (r);
 +		tmp = heap->files[a];
 +		heap->files[a] = heap->files[b];
 +		heap->files[b] = tmp;
 +		a = b;
 +	}
 +}
 +
 +static unsigned int
 +toi(const void *p, int n)
 +{
 +	const unsigned char *v = (const unsigned char *)p;
 +	if (n > 1)
 +		return v[0] + 256 * toi(v + 1, n - 1);
 +	if (n == 1)
 +		return v[0];
 +	return (0);
 +}
 +
 +static time_t
 +isodate7(const unsigned char *v)
 +{
 +	struct tm tm;
 +	int offset;
 +	memset(&tm, 0, sizeof(tm));
 +	tm.tm_year = v[0];
 +	tm.tm_mon = v[1] - 1;
 +	tm.tm_mday = v[2];
 +	tm.tm_hour = v[3];
 +	tm.tm_min = v[4];
 +	tm.tm_sec = v[5];
 +	/* v[6] is the signed timezone offset, in 1/4-hour increments. */
 +	offset = ((const signed char *)v)[6];
 +	if (offset > -48 && offset < 52) {
 +		tm.tm_hour -= offset / 4;
 +		tm.tm_min -= (offset % 4) * 15;
 +	}
 +	return (time_from_tm(&tm));
 +}
 +
 +static time_t
 +isodate17(const unsigned char *v)
 +{
 +	struct tm tm;
 +	int offset;
 +	memset(&tm, 0, sizeof(tm));
 +	tm.tm_year = (v[0] - '0') * 1000 + (v[1] - '0') * 100
 +	    + (v[2] - '0') * 10 + (v[3] - '0')
 +	    - 1900;
 +	tm.tm_mon = (v[4] - '0') * 10 + (v[5] - '0');
 +	tm.tm_mday = (v[6] - '0') * 10 + (v[7] - '0');
 +	tm.tm_hour = (v[8] - '0') * 10 + (v[9] - '0');
 +	tm.tm_min = (v[10] - '0') * 10 + (v[11] - '0');
 +	tm.tm_sec = (v[12] - '0') * 10 + (v[13] - '0');
 +	/* v[16] is the signed timezone offset, in 1/4-hour increments. */
 +	offset = ((const signed char *)v)[16];
 +	if (offset > -48 && offset < 52) {
 +		tm.tm_hour -= offset / 4;
 +		tm.tm_min -= (offset % 4) * 15;
 +	}
 +	return (time_from_tm(&tm));
 +}
 +
 +static time_t
 +time_from_tm(struct tm *t)
 +{
 +#if HAVE_TIMEGM
 +	/* Use platform timegm() if available. */
 +	return (timegm(t));
 +#elif HAVE__MKGMTIME64
 +	return (_mkgmtime64(t));
 +#else
 +	/* Else use direct calculation using POSIX assumptions. */
 +	/* First, fix up tm_yday based on the year/month/day. */
 +	mktime(t);
 +	/* Then we can compute timegm() from first principles. */
 +	return (t->tm_sec + t->tm_min * 60 + t->tm_hour * 3600
 +	    + t->tm_yday * 86400 + (t->tm_year - 70) * 31536000
 +	    + ((t->tm_year - 69) / 4) * 86400 -
 +	    ((t->tm_year - 1) / 100) * 86400
 +	    + ((t->tm_year + 299) / 400) * 86400);
 +#endif
 +}
 +
 +static const char *
 +build_pathname(struct archive_string *as, struct file_info *file)
 +{
 +	if (file->parent != NULL && archive_strlen(&file->parent->name) > 0) {
 +		build_pathname(as, file->parent);
 +		archive_strcat(as, "/");
 +	}
 +	if (archive_strlen(&file->name) == 0)
 +		archive_strcat(as, ".");
 +	else
 +		archive_string_concat(as, &file->name);
 +	return (as->s);
 +}
 +
 +static int
 +build_pathname_utf16be(unsigned char *p, size_t max, size_t *len,
 +    struct file_info *file)
 +{
 +	if (file->parent != NULL && file->parent->utf16be_bytes > 0) {
 +		if (build_pathname_utf16be(p, max, len, file->parent) != 0)
 +			return (-1);
 +		p[*len] = 0;
 +		p[*len + 1] = '/';
 +		*len += 2;
 +	}
 +	if (file->utf16be_bytes == 0) {
 +		if (*len + 2 > max)
 +			return (-1);/* Path is too long! */
 +		p[*len] = 0;
 +		p[*len + 1] = '.';
 +		*len += 2;
 +	} else {
 +		if (*len + file->utf16be_bytes > max)
 +			return (-1);/* Path is too long! */
 +		memcpy(p + *len, file->utf16be_name, file->utf16be_bytes);
 +		*len += file->utf16be_bytes;
 +	}
 +	return (0);
 +}
 +
 +#if DEBUG
 +static void
 +dump_isodirrec(FILE *out, const unsigned char *isodirrec)
 +{
 +	fprintf(out, " l %d,",
 +	    toi(isodirrec + DR_length_offset, DR_length_size));
 +	fprintf(out, " a %d,",
 +	    toi(isodirrec + DR_ext_attr_length_offset, DR_ext_attr_length_size));
 +	fprintf(out, " ext 0x%x,",
 +	    toi(isodirrec + DR_extent_offset, DR_extent_size));
 +	fprintf(out, " s %d,",
 +	    toi(isodirrec + DR_size_offset, DR_extent_size));
 +	fprintf(out, " f 0x%x,",
 +	    toi(isodirrec + DR_flags_offset, DR_flags_size));
 +	fprintf(out, " u %d,",
 +	    toi(isodirrec + DR_file_unit_size_offset, DR_file_unit_size_size));
 +	fprintf(out, " ilv %d,",
 +	    toi(isodirrec + DR_interleave_offset, DR_interleave_size));
 +	fprintf(out, " seq %d,",
 +	    toi(isodirrec + DR_volume_sequence_number_offset, DR_volume_sequence_number_size));
 +	fprintf(out, " nl %d:",
 +	    toi(isodirrec + DR_name_len_offset, DR_name_len_size));
 +	fprintf(out, " `%.*s'",
 +	    toi(isodirrec + DR_name_len_offset, DR_name_len_size), isodirrec + DR_name_offset);
 +}
 +#endif
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
index f751874,0000000..d150802
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
@@@ -1,1233 -1,0 +1,1266 @@@
 +/*-
 + * Copyright (c) 2004 Tim Kientzle
 + * 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: head/lib/libarchive/archive_read_support_format_zip.c 201102 2009-12-28 03:11:36Z kientzle $");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_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"
 +
 +#ifndef HAVE_ZLIB_H
 +#include "archive_crc32.h"
 +#endif
 +
 +struct zip_entry {
 +	int64_t			local_header_offset;
 +	int64_t			compressed_size;
 +	int64_t			uncompressed_size;
 +	int64_t			gid;
 +	int64_t			uid;
 +	struct archive_entry	*entry;
 +	time_t			mtime;
 +	time_t			atime;
 +	time_t			ctime;
 +	uint32_t		crc32;
 +	uint16_t		mode;
 +	uint16_t		flags;
 +	char			compression;
 +	char			system;
 +};
 +
 +struct zip {
 +	/* Structural information about the archive. */
 +	int64_t			central_directory_offset;
 +	size_t			central_directory_size;
 +	size_t			central_directory_entries;
 +	char			have_central_directory;
 +
 +	/* List of entries (seekable Zip only) */
 +	size_t			entries_remaining;
 +	struct zip_entry	*zip_entries;
 +	struct zip_entry	*entry;
 +
 +	size_t			unconsumed;
 +
 +	/* entry_bytes_remaining is the number of bytes we expect. */
 +	int64_t			entry_bytes_remaining;
 +
 +	/* These count the number of bytes actually read for the entry. */
 +	int64_t			entry_compressed_bytes_read;
 +	int64_t			entry_uncompressed_bytes_read;
 +
 +	/* Running CRC32 of the decompressed data */
 +	unsigned long		entry_crc32;
 +
 +	/* Flags to mark progress of decompression. */
 +	char			decompress_init;
 +	char			end_of_entry;
 +
 +	ssize_t			filename_length;
 +	ssize_t			extra_length;
 +
 +	unsigned char 		*uncompressed_buffer;
 +	size_t 			uncompressed_buffer_size;
 +#ifdef HAVE_ZLIB_H
 +	z_stream		stream;
 +	char			stream_valid;
 +#endif
 +
 +	struct archive_string	extra;
 +	struct archive_string_conv *sconv;
 +	struct archive_string_conv *sconv_default;
 +	struct archive_string_conv *sconv_utf8;
 +	int			init_default_conversion;
 +	char	format_name[64];
 +};
 +
 +#define ZIP_LENGTH_AT_END	8
++#define ZIP_ENCRYPTED		(1<<0)	
++#define ZIP_STRONG_ENCRYPTED	(1<<6)	
 +#define ZIP_UTF8_NAME		(1<<11)	
 +
 +static int	archive_read_format_zip_streamable_bid(struct archive_read *, int);
 +static int	archive_read_format_zip_seekable_bid(struct archive_read *, int);
 +static int	archive_read_format_zip_options(struct archive_read *,
 +		    const char *, const char *);
 +static int	archive_read_format_zip_cleanup(struct archive_read *);
 +static int	archive_read_format_zip_read_data(struct archive_read *,
 +		    const void **, size_t *, int64_t *);
 +static int	archive_read_format_zip_read_data_skip(struct archive_read *a);
 +static int	archive_read_format_zip_seekable_read_header(struct archive_read *,
 +		    struct archive_entry *);
 +static int	archive_read_format_zip_streamable_read_header(struct archive_read *,
 +		    struct archive_entry *);
 +#ifdef HAVE_ZLIB_H
 +static int	zip_read_data_deflate(struct archive_read *a, const void **buff,
 +		    size_t *size, int64_t *offset);
 +#endif
 +static int	zip_read_data_none(struct archive_read *a, const void **buff,
 +		    size_t *size, int64_t *offset);
 +static int	zip_read_local_file_header(struct archive_read *a,
 +    struct archive_entry *entry, struct zip *);
 +static time_t	zip_time(const char *);
 +static const char *compression_name(int compression);
 +static void process_extra(const char *, size_t, struct zip_entry *);
 +
 +int
 +archive_read_support_format_zip_streamable(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct zip *zip;
 +	int r;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_read_support_format_zip");
 +
 +	zip = (struct zip *)malloc(sizeof(*zip));
 +	if (zip == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate zip data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	memset(zip, 0, sizeof(*zip));
 +
 +	r = __archive_read_register_format(a,
 +	    zip,
 +	    "zip",
 +	    archive_read_format_zip_streamable_bid,
 +	    archive_read_format_zip_options,
 +	    archive_read_format_zip_streamable_read_header,
 +	    archive_read_format_zip_read_data,
 +	    archive_read_format_zip_read_data_skip,
 +	    archive_read_format_zip_cleanup);
 +
 +	if (r != ARCHIVE_OK)
 +		free(zip);
 +	return (ARCHIVE_OK);
 +}
 +
 +int
 +archive_read_support_format_zip_seekable(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct zip *zip;
 +	int r;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_read_support_format_zip_seekable");
 +
 +	zip = (struct zip *)malloc(sizeof(*zip));
 +	if (zip == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate zip data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	memset(zip, 0, sizeof(*zip));
 +
 +	r = __archive_read_register_format(a,
 +	    zip,
 +	    "zip",
 +	    archive_read_format_zip_seekable_bid,
 +	    archive_read_format_zip_options,
 +	    archive_read_format_zip_seekable_read_header,
 +	    archive_read_format_zip_read_data,
 +	    archive_read_format_zip_read_data_skip,
 +	    archive_read_format_zip_cleanup);
 +
 +	if (r != ARCHIVE_OK)
 +		free(zip);
 +	return (ARCHIVE_OK);
 +}
 +
 +int
 +archive_read_support_format_zip(struct archive *a)
 +{
 +	int r;
 +	r = archive_read_support_format_zip_streamable(a);
 +	if (r != ARCHIVE_OK)
 +		return r;
 +	return (archive_read_support_format_zip_seekable(a));
 +}
 +
 +/*
 + * TODO: This is a performance sink because it forces
 + * the read core to drop buffered data from the start
 + * of file, which will then have to be re-read again
 + * if this bidder loses.
 + *
 + * Consider passing in the winning bid value to subsequent
 + * bidders so that this bidder in particular can avoid
 + * seeking if it knows it's going to lose anyway.
 + */
 +static int
 +archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
 +{
 +	struct zip *zip = (struct zip *)a->format->data;
 +	int64_t filesize;
 +	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);
 +
 +	filesize = __archive_read_seek(a, -22, SEEK_END);
 +	/* If we can't seek, then we can't bid. */
 +	if (filesize <= 0)
 +		return 0;
 +
 +	/* TODO: More robust search for end of central directory record. */
 +	if ((p = __archive_read_ahead(a, 22, NULL)) == NULL)
 +		return 0;
 +	/* First four bytes are signature for end of central directory
 +	   record.  Four zero bytes ensure this isn't a multi-volume
 +	   Zip file (which we don't yet support). */
 +	if (memcmp(p, "PK\005\006\000\000\000\000", 8) != 0)
 +		return 0;
 +
 +	/* Since we've already done the hard work of finding the
 +	   end of central directory record, let's save the important
 +	   information. */
 +	zip->central_directory_entries = archive_le16dec(p + 10);
 +	zip->central_directory_size = archive_le32dec(p + 12);
 +	zip->central_directory_offset = archive_le32dec(p + 16);
 +
 +	/* Just one volume, so central dir must all be on this volume. */
 +	if (zip->central_directory_entries != archive_le16dec(p + 8))
 +		return 0;
 +	/* Central directory can't extend beyond end of this file. */
 +	if (zip->central_directory_offset + zip->central_directory_size > filesize)
 +		return 0;
 +
 +	/* This is just a tiny bit higher than the maximum returned by
 +	   the streaming Zip bidder.  This ensures that the more accurate
 +	   seeking Zip parser wins whenever seek is available. */
 +	return 32;
 +}
 +
 +static int
 +slurp_central_directory(struct archive_read *a, struct zip *zip)
 +{
 +	unsigned i;
 +
 +	__archive_read_seek(a, zip->central_directory_offset, SEEK_SET);
 +
 +	zip->zip_entries = calloc(zip->central_directory_entries, sizeof(struct zip_entry));
 +	for (i = 0; i < zip->central_directory_entries; ++i) {
 +		struct zip_entry *zip_entry = &zip->zip_entries[i];
 +		size_t filename_length, extra_length, comment_length;
 +		uint32_t external_attributes;
 +		const char *p;
 +
 +		if ((p = __archive_read_ahead(a, 46, NULL)) == NULL)
 +			return ARCHIVE_FATAL;
 +		if (memcmp(p, "PK\001\002", 4) != 0) {
 +			archive_set_error(&a->archive,
 +			    -1, "Invalid central directory signature");
 +			return ARCHIVE_FATAL;
 +		}
 +		zip->have_central_directory = 1;
 +		/* version = p[4]; */
 +		zip_entry->system = p[5];
 +		/* version_required = archive_le16dec(p + 6); */
 +		zip_entry->flags = archive_le16dec(p + 8);
 +		zip_entry->compression = archive_le16dec(p + 10);
 +		zip_entry->mtime = zip_time(p + 12);
 +		zip_entry->crc32 = archive_le32dec(p + 16);
 +		zip_entry->compressed_size = archive_le32dec(p + 20);
 +		zip_entry->uncompressed_size = archive_le32dec(p + 24);
 +		filename_length = archive_le16dec(p + 28);
 +		extra_length = archive_le16dec(p + 30);
 +		comment_length = archive_le16dec(p + 32);
 +		/* disk_start = archive_le16dec(p + 34); */ /* Better be zero. */
 +		/* internal_attributes = archive_le16dec(p + 36); */ /* text bit */
 +		external_attributes = archive_le32dec(p + 38);
 +		zip_entry->local_header_offset = archive_le32dec(p + 42);
 +
 +		if (zip_entry->system == 3) {
 +			zip_entry->mode = external_attributes >> 16;
 +		} else {
 +			zip_entry->mode = AE_IFREG | 0777;
 +		}
 +
 +		/* Do we need to parse filename here? */
 +		/* Or can we wait until we read the local header? */
 +		__archive_read_consume(a,
 +		    46 + filename_length + extra_length + comment_length);
 +	}
 +
 +	/* TODO: Sort zip entries. */
 +
 +	return ARCHIVE_OK;
 +}
 +
 +static int
 +archive_read_format_zip_seekable_read_header(struct archive_read *a,
 +	struct archive_entry *entry)
 +{
 +	struct zip *zip = (struct zip *)a->format->data;
 +	int r;
 +
 +	a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
 +	if (a->archive.archive_format_name == NULL)
 +		a->archive.archive_format_name = "ZIP";
 +
 +	if (zip->zip_entries == NULL) {
 +		r = slurp_central_directory(a, zip);
 +		zip->entries_remaining = zip->central_directory_entries;
 +		if (r != ARCHIVE_OK)
 +			return r;
 +		zip->entry = zip->zip_entries;
 +	} else {
 +		++zip->entry;
 +	}
 +
 +	if (zip->entries_remaining <= 0)
 +		return ARCHIVE_EOF;
 +	--zip->entries_remaining;
 +
 +	/* TODO: If entries are sorted by offset within the file, we
 +	   should be able to skip here instead of seeking.  Skipping is
 +	   typically faster (easier for I/O layer to optimize). */
 +	__archive_read_seek(a, zip->entry->local_header_offset, SEEK_SET);
 +	zip->unconsumed = 0;
- 	return zip_read_local_file_header(a, entry, zip);
++	r = zip_read_local_file_header(a, entry, zip);
++	if (r != ARCHIVE_OK)
++		return r;
++	if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) {
++		const void *p;
++		size_t linkname_length = archive_entry_size(entry);
++
++		archive_entry_set_size(entry, 0);
++		p = __archive_read_ahead(a, linkname_length, NULL);
++		if (p == NULL) {
++			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++			    "Truncated Zip file");
++			return ARCHIVE_FATAL;
++		}
++
++		if (archive_entry_copy_symlink_l(entry, p, linkname_length,
++		    NULL) != 0) {
++			/* NOTE: If the last argument is NULL, this will
++			 * fail only by memeory allocation failure. */
++			archive_set_error(&a->archive, ENOMEM,
++			    "Can't allocate memory for Symlink");
++			return (ARCHIVE_FATAL);
++		}
++		/* TODO: handle character-set issues? */
++	}
++	return ARCHIVE_OK;
 +}
 +
 +static int
 +archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid)
 +{
 +	const char *p;
 +
 +	(void)best_bid; /* UNUSED */
 +
 +	if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)
 +		return (-1);
 +
 +	/*
 +	 * Bid of 30 here is: 16 bits for "PK",
 +	 * next 16-bit field has four options (-2 bits).
 +	 * 16 + 16-2 = 30.
 +	 */
 +	if (p[0] == 'P' && p[1] == 'K') {
 +		if ((p[2] == '\001' && p[3] == '\002')
 +		    || (p[2] == '\003' && p[3] == '\004')
 +		    || (p[2] == '\005' && p[3] == '\006')
 +		    || (p[2] == '\007' && p[3] == '\010')
 +		    || (p[2] == '0' && p[3] == '0'))
 +			return (30);
 +	}
 +
 +	return (0);
 +}
 +
 +static int
 +archive_read_format_zip_options(struct archive_read *a,
 +    const char *key, const char *val)
 +{
 +	struct zip *zip;
 +	int ret = ARCHIVE_FAILED;
 +
 +	zip = (struct zip *)(a->format->data);
 +	if (strcmp(key, "compat-2x")  == 0) {
 +		/* Handle filnames as libarchive 2.x */
 +		zip->init_default_conversion = (val != NULL) ? 1 : 0;
 +		ret = ARCHIVE_OK;
 +	} else if (strcmp(key, "hdrcharset")  == 0) {
 +		if (val == NULL || val[0] == 0)
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "zip: hdrcharset option needs a character-set name");
 +		else {
 +			zip->sconv = archive_string_conversion_from_charset(
 +			    &a->archive, val, 0);
 +			if (zip->sconv != NULL) {
 +				if (strcmp(val, "UTF-8") == 0)
 +					zip->sconv_utf8 = zip->sconv;
 +				ret = ARCHIVE_OK;
 +			} else
 +				ret = ARCHIVE_FATAL;
 +		}
 +	} else
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "zip: unknown keyword ``%s''", key);
 +
 +	return (ret);
 +}
 +
 +static int
 +archive_read_format_zip_streamable_read_header(struct archive_read *a,
 +    struct archive_entry *entry)
 +{
 +	struct zip *zip;
 +
 +	a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
 +	if (a->archive.archive_format_name == NULL)
 +		a->archive.archive_format_name = "ZIP";
 +
 +	zip = (struct zip *)(a->format->data);
 +
 +	/* Make sure we have a zip_entry structure to use. */
 +	if (zip->zip_entries == NULL) {
 +		zip->zip_entries = malloc(sizeof(struct zip_entry));
 +		if (zip->zip_entries == NULL) {
 +			archive_set_error(&a->archive, ENOMEM, "Out  of memory");
 +			return ARCHIVE_FATAL;
 +		}
 +	}
 +	zip->entry = zip->zip_entries;
 +	memset(zip->entry, 0, sizeof(struct zip_entry));
 +
 +	/* Search ahead for the next local file header. */
 +	__archive_read_consume(a, zip->unconsumed);
 +	zip->unconsumed = 0;
 +	for (;;) {
 +		int64_t skipped = 0;
 +		const char *p, *end;
 +		ssize_t bytes;
 +
 +		p = __archive_read_ahead(a, 4, &bytes);
 +		if (p == NULL)
 +			return (ARCHIVE_FATAL);
 +		end = p + bytes;
 +
 +		while (p + 4 <= end) {
 +			if (p[0] == 'P' && p[1] == 'K') {
 +				if (p[2] == '\001' && p[3] == '\002')
 +					/* Beginning of central directory. */
 +					return (ARCHIVE_EOF);
 +
 +				if (p[2] == '\003' && p[3] == '\004') {
 +					/* Regular file entry. */
 +					__archive_read_consume(a, skipped);
 +					return zip_read_local_file_header(a, entry, zip);
 +				}
 +
 +				if (p[2] == '\005' && p[3] == '\006')
 +					/* End of central directory. */
 +					return (ARCHIVE_EOF);
 +			}
 +			++p;
 +			++skipped;
 +		}
 +		__archive_read_consume(a, skipped);
 +	}
 +}
 +
 +/*
 + * Assumes file pointer is at beginning of local file header.
 + */
 +static int
 +zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
 +    struct zip *zip)
 +{
 +	const char *p;
 +	const void *h;
 +	const wchar_t *wp;
 +	const char *cp;
 +	size_t len, filename_length, extra_length;
 +	struct archive_string_conv *sconv;
 +	struct zip_entry *zip_entry = zip->entry;
 +	uint32_t local_crc32;
 +	int64_t compressed_size, uncompressed_size;
 +	int ret = ARCHIVE_OK;
 +	char version;
 +
 +	zip->decompress_init = 0;
 +	zip->end_of_entry = 0;
 +	zip->entry_uncompressed_bytes_read = 0;
 +	zip->entry_compressed_bytes_read = 0;
 +	zip->entry_crc32 = crc32(0, NULL, 0);
 +
 +	/* Setup default conversion. */
 +	if (zip->sconv == NULL && !zip->init_default_conversion) {
 +		zip->sconv_default =
 +		    archive_string_default_conversion_for_read(&(a->archive));
 +		zip->init_default_conversion = 1;
 +	}
 +
 +	if ((p = __archive_read_ahead(a, 30, NULL)) == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated ZIP file header");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	if (memcmp(p, "PK\003\004", 4) != 0) {
 +		archive_set_error(&a->archive, -1, "Damaged Zip archive");
 +		return ARCHIVE_FATAL;
 +	}
 +	version = p[4];
 +	zip_entry->system = p[5];
 +	zip_entry->flags = archive_le16dec(p + 6);
 +	zip_entry->compression = archive_le16dec(p + 8);
 +	zip_entry->mtime = zip_time(p + 10);
 +	local_crc32 = archive_le32dec(p + 14);
 +	compressed_size = archive_le32dec(p + 18);
 +	uncompressed_size = archive_le32dec(p + 22);
 +	filename_length = archive_le16dec(p + 26);
 +	extra_length = archive_le16dec(p + 28);
 +
 +	__archive_read_consume(a, 30);
 +
 +	if (zip->have_central_directory) {
 +		/* If we read the central dir entry, we must have size information
 +		   as well, so ignore the length-at-end flag. */
 +		zip_entry->flags &= ~ZIP_LENGTH_AT_END;
 +		/* If we have values from both the local file header
 +		   and the central directory, warn about mismatches
 +		   which might indicate a damaged file.  But some
 +		   writers always put zero in the local header; don't
 +		   bother warning about that. */
 +		if (local_crc32 != 0 && local_crc32 != zip_entry->crc32) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Inconsistent CRC32 values");
 +			ret = ARCHIVE_WARN;
 +		}
 +		if (compressed_size != 0
 +		    && compressed_size != zip_entry->compressed_size) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Inconsistent compressed size");
 +			ret = ARCHIVE_WARN;
 +		}
 +		if (uncompressed_size != 0
 +		    && uncompressed_size != zip_entry->uncompressed_size) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Inconsistent uncompressed size");
 +			ret = ARCHIVE_WARN;
 +		}
 +	} else {
 +		/* If we don't have the CD info, use whatever we do have. */
 +		zip_entry->crc32 = local_crc32;
 +		zip_entry->compressed_size = compressed_size;
 +		zip_entry->uncompressed_size = uncompressed_size;
 +	}
 +
 +	/* Read the filename. */
 +	if ((h = __archive_read_ahead(a, filename_length, NULL)) == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated ZIP file header");
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (zip_entry->flags & ZIP_UTF8_NAME) {
 +		/* The filename is stored to be UTF-8. */
 +		if (zip->sconv_utf8 == NULL) {
 +			zip->sconv_utf8 =
 +			    archive_string_conversion_from_charset(
 +				&a->archive, "UTF-8", 1);
 +			if (zip->sconv_utf8 == NULL)
 +				return (ARCHIVE_FATAL);
 +		}
 +		sconv = zip->sconv_utf8;
 +	} else if (zip->sconv != NULL)
 +		sconv = zip->sconv;
 +	else
 +		sconv = zip->sconv_default;
 +
 +	if (archive_entry_copy_pathname_l(entry,
 +	    h, filename_length, 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));
 +		ret = ARCHIVE_WARN;
 +	}
 +	__archive_read_consume(a, filename_length);
 +
 +	if (zip_entry->mode == 0) {
 +		/* Especially in streaming mode, we can end up
 +		   here without having seen any mode information.
 +		   Guess from the filename. */
 +		wp = archive_entry_pathname_w(entry);
 +		if (wp != NULL) {
 +			len = wcslen(wp);
 +			if (len > 0 && wp[len - 1] == L'/')
 +				zip_entry->mode = AE_IFDIR | 0777;
 +			else
 +				zip_entry->mode = AE_IFREG | 0777;
 +		} else {
 +			cp = archive_entry_pathname(entry);
 +			len = (cp != NULL)?strlen(cp):0;
 +			if (len > 0 && cp[len - 1] == '/')
 +				zip_entry->mode = AE_IFDIR | 0777;
 +			else
 +				zip_entry->mode = AE_IFREG | 0777;
 +		}
 +	}
 +
 +	/* Read the extra data. */
 +	if ((h = __archive_read_ahead(a, extra_length, NULL)) == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated ZIP file header");
 +		return (ARCHIVE_FATAL);
 +	}
 +	process_extra(h, extra_length, zip_entry);
 +	__archive_read_consume(a, extra_length);
 +
 +	/* Populate some additional entry fields: */
 +	archive_entry_set_mode(entry, zip_entry->mode);
 +	archive_entry_set_uid(entry, zip_entry->uid);
 +	archive_entry_set_gid(entry, zip_entry->gid);
 +	archive_entry_set_mtime(entry, zip_entry->mtime, 0);
 +	archive_entry_set_ctime(entry, zip_entry->ctime, 0);
 +	archive_entry_set_atime(entry, zip_entry->atime, 0);
 +	/* Set the size only if it's meaningful. */
 +	if (0 == (zip_entry->flags & ZIP_LENGTH_AT_END))
 +		archive_entry_set_size(entry, zip_entry->uncompressed_size);
 +
 +	zip->entry_bytes_remaining = zip_entry->compressed_size;
 +
 +	/* If there's no body, force read_data() to return EOF immediately. */
 +	if (0 == (zip_entry->flags & ZIP_LENGTH_AT_END)
 +	    && zip->entry_bytes_remaining < 1)
 +		zip->end_of_entry = 1;
 +
 +	/* Set up a more descriptive format name. */
 +	sprintf(zip->format_name, "ZIP %d.%d (%s)",
 +	    version / 10, version % 10,
 +	    compression_name(zip->entry->compression));
 +	a->archive.archive_format_name = zip->format_name;
 +
 +	return (ret);
 +}
 +
 +static const char *
 +compression_name(int compression)
 +{
 +	static const char *compression_names[] = {
 +		"uncompressed",
 +		"shrinking",
 +		"reduced-1",
 +		"reduced-2",
 +		"reduced-3",
 +		"reduced-4",
 +		"imploded",
 +		"reserved",
 +		"deflation"
 +	};
 +
 +	if (compression <
 +	    sizeof(compression_names)/sizeof(compression_names[0]))
 +		return compression_names[compression];
 +	else
 +		return "??";
 +}
 +
 +/* Convert an MSDOS-style date/time into Unix-style time. */
 +static time_t
 +zip_time(const char *p)
 +{
 +	int msTime, msDate;
 +	struct tm ts;
 +
 +	msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]);
 +	msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]);
 +
 +	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);
 +}
 +
 +static int
 +archive_read_format_zip_read_data(struct archive_read *a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +	int r;
 +	struct zip *zip = (struct zip *)(a->format->data);
 +
 +	*offset = zip->entry_uncompressed_bytes_read;
 +	*size = 0;
 +	*buff = NULL;
 +
 +	/* If we hit end-of-entry last time, return ARCHIVE_EOF. */
 +	if (zip->end_of_entry)
 +		return (ARCHIVE_EOF);
 +
 +	/* Return EOF immediately if this is a non-regular file. */
 +	if (AE_IFREG != (zip->entry->mode & AE_IFMT))
 +		return (ARCHIVE_EOF);
 +
++	if (zip->entry->flags & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)) {
++		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++		    "Encrypted file is unsupported");
++		return (ARCHIVE_FAILED);
++	}
++
 +	__archive_read_consume(a, zip->unconsumed);
 +	zip->unconsumed = 0;
 +
 +	switch(zip->entry->compression) {
 +	case 0:  /* No compression. */
 +		r =  zip_read_data_none(a, buff, size, offset);
 +		break;
 +#ifdef HAVE_ZLIB_H
 +	case 8: /* Deflate compression. */
 +		r =  zip_read_data_deflate(a, buff, size, offset);
 +		break;
 +#endif
 +	default: /* Unsupported compression. */
 +		/* Return a warning. */
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Unsupported ZIP compression method (%s)",
 +		    compression_name(zip->entry->compression));
 +		/* We can't decompress this entry, but we will
 +		 * be able to skip() it and try the next entry. */
 +		return (ARCHIVE_FAILED);
 +		break;
 +	}
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* Update checksum */
 +	if (*size)
 +		zip->entry_crc32 = crc32(zip->entry_crc32, *buff, *size);
 +	/* If we hit the end, swallow any end-of-data marker. */
 +	if (zip->end_of_entry) {
 +		/* Check file size, CRC against these values. */
 +		if (zip->entry->compressed_size != zip->entry_compressed_bytes_read) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "ZIP compressed data is wrong size (read %jd, expected %jd)",
 +			    (intmax_t)zip->entry_compressed_bytes_read,
 +			    (intmax_t)zip->entry->compressed_size);
 +			return (ARCHIVE_WARN);
 +		}
 +		/* Size field only stores the lower 32 bits of the actual
 +		 * size. */
 +		if ((zip->entry->uncompressed_size & UINT32_MAX)
 +		    != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "ZIP uncompressed data is wrong size (read %jd, expected %jd)",
 +			    (intmax_t)zip->entry_uncompressed_bytes_read,
 +			    (intmax_t)zip->entry->uncompressed_size);
 +			return (ARCHIVE_WARN);
 +		}
 +		/* Check computed CRC against header */
 +		if (zip->entry->crc32 != zip->entry_crc32) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "ZIP bad CRC: 0x%lx should be 0x%lx",
 +			    (unsigned long)zip->entry_crc32,
 +			    (unsigned long)zip->entry->crc32);
 +			return (ARCHIVE_WARN);
 +		}
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Read "uncompressed" data.  There are three cases:
 + *  1) We know the size of the data.  This is always true for the
 + * seeking reader (we've examined the Central Directory already).
 + *  2) ZIP_LENGTH_AT_END was set, but only the CRC was deferred.
 + * Info-ZIP seems to do this; we know the size but have to grab
 + * the CRC from the data descriptor afterwards.
 + *  3) We're streaming and ZIP_LENGTH_AT_END was specified and
 + * we have no size information.  In this case, we can do pretty
 + * well by watching for the data descriptor record.  The data
 + * descriptor is 16 bytes and includes a computed CRC that should
 + * provide a strong check.
 + *
 + * TODO: Technically, the PK\007\010 signature is optional.
 + * In the original spec, the data descriptor contained CRC
 + * and size fields but had no leading signature.  In practice,
 + * newer writers seem to provide the signature pretty consistently,
 + * but we might need to do something more complex here if
 + * we want to handle older archives that lack that signature.
 + *
 + * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
 + * zip->end_of_entry if it consumes all of the data.
 + */
 +static int
 +zip_read_data_none(struct archive_read *a, const void **_buff,
 +    size_t *size, int64_t *offset)
 +{
 +	struct zip *zip;
 +	const char *buff;
 +	ssize_t bytes_avail;
 +
 +	zip = (struct zip *)(a->format->data);
 +
 +	if (zip->entry->flags & ZIP_LENGTH_AT_END) {
 +		const char *p;
 +
 +		/* Grab at least 16 bytes. */
 +		buff = __archive_read_ahead(a, 16, &bytes_avail);
 +		if (bytes_avail < 16) {
 +			/* Zip archives have end-of-archive markers
 +			   that are longer than this, so a failure to get at
 +			   least 16 bytes really does indicate a truncated
 +			   file. */
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated ZIP file data");
 +			return (ARCHIVE_FATAL);
 +		}
 +		/* Check for a complete PK\007\010 signature. */
 +		p = buff;
 +		if (p[0] == 'P' && p[1] == 'K' 
 +		    && p[2] == '\007' && p[3] == '\010'
 +		    && archive_le32dec(p + 4) == zip->entry_crc32
 +		    && archive_le32dec(p + 8) == zip->entry_compressed_bytes_read
 +		    && archive_le32dec(p + 12) == zip->entry_uncompressed_bytes_read) {
 +			zip->entry->crc32 = archive_le32dec(p + 4);
 +			zip->entry->compressed_size = archive_le32dec(p + 8);
 +			zip->entry->uncompressed_size = archive_le32dec(p + 12);
 +			zip->end_of_entry = 1;
 +			zip->unconsumed = 16;
 +			return (ARCHIVE_OK);
 +		}
 +		/* If not at EOF, ensure we consume at least one byte. */
 +		++p;
 +
 +		/* Scan forward until we see where a PK\007\010 signature might be. */
 +		/* Return bytes up until that point.  On the next call, the code
 +		   above will verify the data descriptor. */
 +		while (p < buff + bytes_avail - 4) {
 +			if (p[3] == 'P') { p += 3; }
 +			else if (p[3] == 'K') { p += 2; }
 +			else if (p[3] == '\007') { p += 1; }
 +			else if (p[3] == '\010' && p[2] == '\007'
 +			    && p[1] == 'K' && p[0] == 'P') {
 +				break;
 +			} else { p += 4; }
 +		}
 +		bytes_avail = p - buff;
 +	} else {
 +		if (zip->entry_bytes_remaining == 0) {
 +			zip->end_of_entry = 1;
 +			return (ARCHIVE_OK);
 +		}
 +		/* Grab a bunch of bytes. */
 +		buff = __archive_read_ahead(a, 1, &bytes_avail);
 +		if (bytes_avail <= 0) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated ZIP file data");
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (bytes_avail > zip->entry_bytes_remaining)
 +			bytes_avail = zip->entry_bytes_remaining;
 +	}
 +	*size = bytes_avail;
 +	zip->entry_bytes_remaining -= bytes_avail;
 +	zip->entry_uncompressed_bytes_read += bytes_avail;
 +	zip->entry_compressed_bytes_read += bytes_avail;
 +	zip->unconsumed += bytes_avail;
 +	*_buff = buff;
 +	return (ARCHIVE_OK);
 +}
 +
 +#ifdef HAVE_ZLIB_H
 +static int
 +zip_read_data_deflate(struct archive_read *a, const void **buff,
 +    size_t *size, int64_t *offset)
 +{
 +	struct zip *zip;
 +	ssize_t bytes_avail;
 +	const void *compressed_buff;
 +	int r;
 +
 +	zip = (struct zip *)(a->format->data);
 +
 +	/* If the buffer hasn't been allocated, allocate it now. */
 +	if (zip->uncompressed_buffer == NULL) {
 +		zip->uncompressed_buffer_size = 256 * 1024;
 +		zip->uncompressed_buffer
 +		    = (unsigned char *)malloc(zip->uncompressed_buffer_size);
 +		if (zip->uncompressed_buffer == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "No memory for ZIP decompression");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	/* If we haven't yet read any data, initialize the decompressor. */
 +	if (!zip->decompress_init) {
 +		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,
 +			    "Can't initialize ZIP decompression.");
 +			return (ARCHIVE_FATAL);
 +		}
 +		/* Stream structure has been set up. */
 +		zip->stream_valid = 1;
 +		/* We've initialized decompression for this stream. */
 +		zip->decompress_init = 1;
 +	}
 +
 +	/*
 +	 * 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.
 +	 */
 +	compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);
 +	if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END)
 +	    && bytes_avail > zip->entry_bytes_remaining) {
 +		bytes_avail = zip->entry_bytes_remaining;
 +	}
 +	if (bytes_avail <= 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated ZIP file body");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * 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'.
 +	 */
 +	zip->stream.next_in = (Bytef *)(uintptr_t)(const void *)compressed_buff;
 +	zip->stream.avail_in = bytes_avail;
 +	zip->stream.total_in = 0;
 +	zip->stream.next_out = zip->uncompressed_buffer;
 +	zip->stream.avail_out = zip->uncompressed_buffer_size;
 +	zip->stream.total_out = 0;
 +
 +	r = inflate(&zip->stream, 0);
 +	switch (r) {
 +	case Z_OK:
 +		break;
 +	case Z_STREAM_END:
 +		zip->end_of_entry = 1;
 +		break;
 +	case Z_MEM_ERROR:
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Out of memory for ZIP decompression");
 +		return (ARCHIVE_FATAL);
 +	default:
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "ZIP decompression failed (%d)", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Consume as much as the compressor actually used. */
 +	bytes_avail = zip->stream.total_in;
 +	__archive_read_consume(a, bytes_avail);
 +	zip->entry_bytes_remaining -= bytes_avail;
 +	zip->entry_compressed_bytes_read += bytes_avail;
 +
 +	*size = zip->stream.total_out;
 +	zip->entry_uncompressed_bytes_read += zip->stream.total_out;
 +	*buff = zip->uncompressed_buffer;
 +
 +	if (zip->end_of_entry && (zip->entry->flags & ZIP_LENGTH_AT_END)) {
 +		const char *p;
 +
 +		if (NULL == (p = __archive_read_ahead(a, 16, NULL))) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated ZIP end-of-file record");
 +			return (ARCHIVE_FATAL);
 +		}
 +		/* Consume the optional PK\007\010 marker. */
 +		if (p[0] == 'P' && p[1] == 'K' && p[2] == '\007' && p[3] == '\010') {
 +			zip->entry->crc32 = archive_le32dec(p + 4);
 +			zip->entry->compressed_size = archive_le32dec(p + 8);
 +			zip->entry->uncompressed_size = archive_le32dec(p + 12);
 +			zip->unconsumed = 16;
 +		}
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +#endif
 +
 +static int
 +archive_read_format_zip_read_data_skip(struct archive_read *a)
 +{
 +	struct zip *zip;
 +
 +	zip = (struct zip *)(a->format->data);
 +
 +	/* If we've already read to end of data, we're done. */
 +	if (zip->end_of_entry)
 +		return (ARCHIVE_OK);
 +	/* If we're seeking, we're done. */
 +	if (zip->have_central_directory)
 +		return (ARCHIVE_OK);
 +
 +	/* So we know we're streaming... */
 +	if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END)) {
 +		/* We know the compressed length, so we can just skip. */
 +		int64_t bytes_skipped = __archive_read_consume(a,
 +		    zip->entry_bytes_remaining + zip->unconsumed);
 +		if (bytes_skipped < 0)
 +			return (ARCHIVE_FATAL);
 +		zip->unconsumed = 0;
 +		return (ARCHIVE_OK);
 +	}
 +
 +	/* We're streaming and we don't know the length. */
 +	/* If the body is compressed and we know the format, we can
 +	 * find an exact end-of-entry by decompressing it. */
 +	switch (zip->entry->compression) {
 +#ifdef HAVE_ZLIB_H
 +	case 8: /* Deflate compression. */
 +		while (!zip->end_of_entry) {
 +			int64_t offset = 0;
 +			const void *buff = NULL;
 +			size_t size = 0;
 +			int r;
 +			r =  zip_read_data_deflate(a, &buff, &size, &offset);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +		}
 +		break;
 +#endif
 +	default: /* Uncompressed or unknown. */
 +		/* Scan for a PK\007\010 signature. */
 +		__archive_read_consume(a, zip->unconsumed);
 +		zip->unconsumed = 0;
 +		for (;;) {
 +			const char *p, *buff;
 +			ssize_t bytes_avail;
 +			buff = __archive_read_ahead(a, 16, &bytes_avail);
 +			if (bytes_avail < 16) {
 +				archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +				    "Truncated ZIP file data");
 +				return (ARCHIVE_FATAL);
 +			}
 +			p = buff;
 +			while (p < buff + bytes_avail - 16) {
 +				if (p[3] == 'P') { p += 3; }
 +				else if (p[3] == 'K') { p += 2; }
 +				else if (p[3] == '\007') { p += 1; }
 +				else if (p[3] == '\010' && p[2] == '\007'
 +				    && p[1] == 'K' && p[0] == 'P') {
 +					__archive_read_consume(a, p - buff + 16);
 +					return ARCHIVE_OK;
 +				} else { p += 4; }
 +			}
 +			__archive_read_consume(a, p - buff);
 +		}
 +	}
 +	return ARCHIVE_OK;
 +}
 +
 +static int
 +archive_read_format_zip_cleanup(struct archive_read *a)
 +{
 +	struct zip *zip;
 +
 +	zip = (struct zip *)(a->format->data);
 +#ifdef HAVE_ZLIB_H
 +	if (zip->stream_valid)
 +		inflateEnd(&zip->stream);
 +#endif
 +	free(zip->zip_entries);
 +	free(zip->uncompressed_buffer);
 +	archive_string_free(&(zip->extra));
 +	free(zip);
 +	(a->format->data) = NULL;
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * The extra data is stored as a list of
 + *	id1+size1+data1 + id2+size2+data2 ...
 + *  triplets.  id and size are 2 bytes each.
 + */
 +static void
 +process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
 +{
 +	unsigned offset = 0;
 +
 +	while (offset < extra_length - 4)
 +	{
 +		unsigned short headerid = archive_le16dec(p + offset);
 +		unsigned short datasize = archive_le16dec(p + offset + 2);
 +		offset += 4;
 +		if (offset + datasize > extra_length)
 +			break;
 +#ifdef DEBUG
 +		fprintf(stderr, "Header id 0x%x, length %d\n",
 +		    headerid, datasize);
 +#endif
 +		switch (headerid) {
 +		case 0x0001:
 +			/* Zip64 extended information extra field. */
 +			if (datasize >= 8)
 +				zip_entry->uncompressed_size =
 +				    archive_le64dec(p + offset);
 +			if (datasize >= 16)
 +				zip_entry->compressed_size =
 +				    archive_le64dec(p + offset + 8);
 +			break;
 +		case 0x5455:
 +		{
 +			/* Extended time field "UT". */
 +			int flags = p[offset];
 +			offset++;
 +			datasize--;
 +			/* Flag bits indicate which dates are present. */
 +			if (flags & 0x01)
 +			{
 +#ifdef DEBUG
 +				fprintf(stderr, "mtime: %lld -> %d\n",
 +				    (long long)zip_entry->mtime,
 +				    archive_le32dec(p + offset));
 +#endif
 +				if (datasize < 4)
 +					break;
 +				zip_entry->mtime = archive_le32dec(p + offset);
 +				offset += 4;
 +				datasize -= 4;
 +			}
 +			if (flags & 0x02)
 +			{
 +				if (datasize < 4)
 +					break;
 +				zip_entry->atime = archive_le32dec(p + offset);
 +				offset += 4;
 +				datasize -= 4;
 +			}
 +			if (flags & 0x04)
 +			{
 +				if (datasize < 4)
 +					break;
 +				zip_entry->ctime = archive_le32dec(p + offset);
 +				offset += 4;
 +				datasize -= 4;
 +			}
 +			break;
 +		}
 +		case 0x5855:
 +		{
 +			/* Info-ZIP Unix Extra Field (old version) "UX". */
 +			if (datasize >= 8) {
 +				zip_entry->atime = archive_le32dec(p + offset);
 +				zip_entry->mtime = archive_le32dec(p + offset + 4);
 +			}
 +			if (datasize >= 12) {
 +				zip_entry->uid = archive_le16dec(p + offset + 8);
 +				zip_entry->gid = archive_le16dec(p + offset + 10);
 +			}
 +			break;
 +		}
 +		case 0x7855:
 +			/* Info-ZIP Unix Extra Field (type 2) "Ux". */
 +#ifdef DEBUG
 +			fprintf(stderr, "uid %d gid %d\n",
 +			    archive_le16dec(p + offset),
 +			    archive_le16dec(p + offset + 2));
 +#endif
 +			if (datasize >= 2)
 +				zip_entry->uid = archive_le16dec(p + offset);
 +			if (datasize >= 4)
 +				zip_entry->gid = archive_le16dec(p + offset + 2);
 +			break;
 +		case 0x7875:
 +		{
 +			/* Info-Zip Unix Extra Field (type 3) "ux". */
 +			int uidsize = 0, gidsize = 0;
 +
 +			if (datasize >= 1 && p[offset] == 1) {/* version=1 */
 +				if (datasize >= 4) {
 +					/* get a uid size. */
 +					uidsize = p[offset+1];
 +					if (uidsize == 2)
 +						zip_entry->uid = archive_le16dec(
 +						     p + offset + 2);
 +					else if (uidsize == 4 && datasize >= 6)
 +						zip_entry->uid = archive_le32dec(
 +						     p + offset + 2);
 +				}
 +				if (datasize >= (2 + uidsize + 3)) {
 +					/* get a gid size. */
 +					gidsize = p[offset+2+uidsize];
 +					if (gidsize == 2)
 +						zip_entry->gid = archive_le16dec(
 +						    p+offset+2+uidsize+1);
 +					else if (gidsize == 4 &&
 +					    datasize >= (2 + uidsize + 5))
 +						zip_entry->gid = archive_le32dec(
 +						    p+offset+2+uidsize+1);
 +				}
 +			}
 +			break;
 +		}
 +		default:
 +			break;
 +		}
 +		offset += datasize;
 +	}
 +#ifdef DEBUG
 +	if (offset != extra_length)
 +	{
 +		fprintf(stderr,
 +		    "Extra data field contents do not match reported size!\n");
 +	}
 +#endif
 +}
diff --cc Utilities/cmlibarchive/libarchive/archive_string.c
index 5bd09bd,0000000..cbfad2c
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_string.c
+++ b/Utilities/cmlibarchive/libarchive/archive_string.c
@@@ -1,4228 -1,0 +1,4237 @@@
 +/*-
 + * Copyright (c) 2003-2011 Tim Kientzle
 + * 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: head/lib/libarchive/archive_string.c 201095 2009-12-28 02:33:22Z kientzle $");
 +
 +/*
 + * Basic resizable string support, to simplify manipulating arbitrary-sized
 + * strings while minimizing heap activity.
 + *
 + * In particular, the buffer used by a string object is only grown, it
 + * never shrinks, so you can clear and reuse the same string object
 + * without incurring additional memory allocations.
 + */
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_ICONV_H
 +#include <iconv.h>
 +#endif
 +#ifdef HAVE_LANGINFO_H
 +#include <langinfo.h>
 +#endif
 +#ifdef HAVE_LOCALCHARSET_H
 +#include <localcharset.h>
 +#endif
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STRING_H
 +#include <string.h>
 +#endif
 +#ifdef HAVE_WCHAR_H
 +#include <wchar.h>
 +#endif
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +#include <windows.h>
 +#include <locale.h>
 +#endif
 +#if defined(__APPLE__)
 +#include <CoreServices/CoreServices.h>
 +#endif
 +
 +#include "archive_endian.h"
 +#include "archive_private.h"
 +#include "archive_string.h"
 +#include "archive_string_composition.h"
 +
 +#if !defined(HAVE_WMEMCPY) && !defined(wmemcpy)
 +#define wmemcpy(a,b,i)  (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
 +#endif
 +
 +struct archive_string_conv {
 +	struct archive_string_conv	*next;
 +	char				*from_charset;
 +	char				*to_charset;
 +	unsigned			 from_cp;
 +	unsigned			 to_cp;
 +	/* Set 1 if from_charset and to_charset are the same. */
 +	int				 same;
 +	int				 flag;
 +#define SCONV_TO_CHARSET	1	/* MBS is being converted to specified
 +					 * charset. */
 +#define SCONV_FROM_CHARSET	(1<<1)	/* MBS is being converted from
 +					 * specified charset. */
 +#define SCONV_BEST_EFFORT 	(1<<2)	/* Copy at least ASCII code. */
 +#define SCONV_WIN_CP	 	(1<<3)	/* Use Windows API for converting
 +					 * MBS. */
 +#define SCONV_UTF8_LIBARCHIVE_2 (1<<4)	/* Incorrect UTF-8 made by libarchive
 +					 * 2.x in the wrong assumption. */
 +#define SCONV_NORMALIZATION_C	(1<<6)	/* Need normalization to be Form C.
 +					 * Before UTF-8 characters are actually
 +					 * processed. */
 +#define SCONV_NORMALIZATION_D	(1<<7)	/* Need normalization to be Form D.
 +					 * Before UTF-8 characters are actually
 +					 * processed.
 +					 * Currently this only for MAC OS X. */
 +#define SCONV_TO_UTF8		(1<<8)	/* "to charset" side is UTF-8. */
 +#define SCONV_FROM_UTF8		(1<<9)	/* "from charset" side is UTF-8. */
 +#define SCONV_TO_UTF16BE 	(1<<10)	/* "to charset" side is UTF-16BE. */
 +#define SCONV_FROM_UTF16BE 	(1<<11)	/* "from charset" side is UTF-16BE. */
 +#define SCONV_TO_UTF16LE 	(1<<12)	/* "to charset" side is UTF-16LE. */
 +#define SCONV_FROM_UTF16LE 	(1<<13)	/* "from charset" side is UTF-16LE. */
 +#define SCONV_TO_UTF16		(SCONV_TO_UTF16BE | SCONV_TO_UTF16LE)
 +#define SCONV_FROM_UTF16	(SCONV_FROM_UTF16BE | SCONV_FROM_UTF16LE)
 +
 +#if HAVE_ICONV
 +	iconv_t				 cd;
 +	iconv_t				 cd_w;/* Use at archive_mstring on
 +				 	       * Windows. */
 +#endif
 +	/* A temporary buffer for normalization. */
 +	struct archive_string		 utftmp;
 +#if defined(__APPLE__)
 +	UnicodeToTextInfo		 uniInfo;
 +	struct archive_string		 utf16nfc;
 +	struct archive_string		 utf16nfd;
 +#endif
 +	int (*converter[2])(struct archive_string *, const void *, size_t,
 +	    struct archive_string_conv *);
 +	int				 nconverter;
 +};
 +
 +#define CP_C_LOCALE	0	/* "C" locale only for this file. */
 +#define CP_UTF16LE	1200
 +#define CP_UTF16BE	1201
 +
 +#define IS_HIGH_SURROGATE_LA(uc) ((uc) >= 0xD800 && (uc) <= 0xDBFF)
 +#define IS_LOW_SURROGATE_LA(uc)	 ((uc) >= 0xDC00 && (uc) <= 0xDFFF)
 +#define IS_SURROGATE_PAIR_LA(uc) ((uc) >= 0xD800 && (uc) <= 0xDFFF)
 +#define UNICODE_MAX		0x10FFFF
 +#define UNICODE_R_CHAR		0xFFFD	/* Replacement character. */
 +/* Set U+FFFD(Replacement character) in UTF-8. */
 +#define UTF8_SET_R_CHAR(outp) do {		\
 +			(outp)[0] = 0xef;	\
 +			(outp)[1] = 0xbf;	\
 +			(outp)[2] = 0xbd;	\
 +} while (0)
 +#define UTF8_R_CHAR_SIZE	3
 +
 +static struct archive_string_conv *find_sconv_object(struct archive *,
 +	const char *, const char *);
 +static void add_sconv_object(struct archive *, struct archive_string_conv *);
 +static struct archive_string_conv *create_sconv_object(const char *,
 +	const char *, unsigned, int);
 +static void free_sconv_object(struct archive_string_conv *);
 +static struct archive_string_conv *get_sconv_object(struct archive *,
 +	const char *, const char *, int);
 +static unsigned make_codepage_from_charset(const char *);
 +static unsigned get_current_codepage(void);
 +static unsigned get_current_oemcp(void);
 +static size_t mbsnbytes(const void *, size_t);
 +static size_t utf16nbytes(const void *, size_t);
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +static int archive_wstring_append_from_mbs_in_codepage(
 +    struct archive_wstring *, const char *, size_t,
 +    struct archive_string_conv *);
 +static int archive_string_append_from_wcs_in_codepage(struct archive_string *,
 +    const wchar_t *, size_t, struct archive_string_conv *);
 +static int is_big_endian(void);
 +static int strncat_in_codepage(struct archive_string *, const void *,
 +    size_t, struct archive_string_conv *);
 +static int win_strncat_from_utf16be(struct archive_string *, const void *, size_t,
 +    struct archive_string_conv *);
 +static int win_strncat_from_utf16le(struct archive_string *, const void *, size_t,
 +    struct archive_string_conv *);
 +static int win_strncat_to_utf16be(struct archive_string *, const void *, size_t,
 +    struct archive_string_conv *);
 +static int win_strncat_to_utf16le(struct archive_string *, const void *, size_t,
 +    struct archive_string_conv *);
 +#endif
 +static int best_effort_strncat_from_utf16be(struct archive_string *, const void *,
 +    size_t, struct archive_string_conv *);
 +static int best_effort_strncat_from_utf16le(struct archive_string *, const void *,
 +    size_t, struct archive_string_conv *);
 +static int best_effort_strncat_to_utf16be(struct archive_string *, const void *,
 +    size_t, struct archive_string_conv *);
 +static int best_effort_strncat_to_utf16le(struct archive_string *, const void *,
 +    size_t, struct archive_string_conv *);
 +#if defined(HAVE_ICONV)
 +static int iconv_strncat_in_locale(struct archive_string *, const void *,
 +    size_t, struct archive_string_conv *);
 +#endif
 +static int best_effort_strncat_in_locale(struct archive_string *, const void *,
 +    size_t, struct archive_string_conv *);
 +static int _utf8_to_unicode(uint32_t *, const char *, size_t);
 +static int utf8_to_unicode(uint32_t *, const char *, size_t);
 +static inline uint32_t combine_surrogate_pair(uint32_t, uint32_t);
 +static int cesu8_to_unicode(uint32_t *, const char *, size_t);
 +static size_t unicode_to_utf8(char *, size_t, uint32_t);
 +static int utf16_to_unicode(uint32_t *, const char *, size_t, int);
 +static size_t unicode_to_utf16be(char *, size_t, uint32_t);
 +static size_t unicode_to_utf16le(char *, size_t, uint32_t);
 +static int strncat_from_utf8_libarchive2(struct archive_string *,
 +    const void *, size_t, struct archive_string_conv *);
 +static int strncat_from_utf8_to_utf8(struct archive_string *, const void *,
 +    size_t, struct archive_string_conv *);
 +static int archive_string_normalize_C(struct archive_string *, const void *,
 +    size_t, struct archive_string_conv *);
 +#if defined(__APPLE__)
 +static int archive_string_normalize_D(struct archive_string *, const void *,
 +    size_t, struct archive_string_conv *);
 +#endif
 +static int archive_string_append_unicode(struct archive_string *,
 +    const void *, size_t, struct archive_string_conv *);
 +
 +static struct archive_string *
 +archive_string_append(struct archive_string *as, const char *p, size_t s)
 +{
 +	if (archive_string_ensure(as, as->length + s + 1) == NULL)
- 		__archive_errx(1, "Out of memory");
++		return (NULL);
 +	memcpy(as->s + as->length, p, s);
 +	as->length += s;
 +	as->s[as->length] = 0;
 +	return (as);
 +}
 +
 +static struct archive_wstring *
 +archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s)
 +{
 +	if (archive_wstring_ensure(as, as->length + s + 1) == NULL)
- 		__archive_errx(1, "Out of memory");
++		return (NULL);
 +	wmemcpy(as->s + as->length, p, s);
 +	as->length += s;
 +	as->s[as->length] = 0;
 +	return (as);
 +}
 +
 +void
 +archive_string_concat(struct archive_string *dest, struct archive_string *src)
 +{
- 	archive_string_append(dest, src->s, src->length);
++	if (archive_string_append(dest, src->s, src->length) == NULL)
++		__archive_errx(1, "Out of memory");
 +}
 +
 +void
 +archive_wstring_concat(struct archive_wstring *dest, struct archive_wstring *src)
 +{
- 	archive_wstring_append(dest, src->s, src->length);
++	if (archive_wstring_append(dest, src->s, src->length) == NULL)
++		__archive_errx(1, "Out of memory");
 +}
 +
 +void
 +archive_string_free(struct archive_string *as)
 +{
 +	as->length = 0;
 +	as->buffer_length = 0;
 +	free(as->s);
 +	as->s = NULL;
 +}
 +
 +void
 +archive_wstring_free(struct archive_wstring *as)
 +{
 +	as->length = 0;
 +	as->buffer_length = 0;
 +	free(as->s);
 +	as->s = NULL;
 +}
 +
 +struct archive_wstring *
 +archive_wstring_ensure(struct archive_wstring *as, size_t s)
 +{
 +	return (struct archive_wstring *)
 +		archive_string_ensure((struct archive_string *)as,
 +					s * sizeof(wchar_t));
 +}
 +
 +/* Returns NULL on any allocation failure. */
 +struct archive_string *
 +archive_string_ensure(struct archive_string *as, size_t s)
 +{
 +	char *p;
 +	size_t new_length;
 +
 +	/* If buffer is already big enough, don't reallocate. */
 +	if (as->s && (s <= as->buffer_length))
 +		return (as);
 +
 +	/*
 +	 * Growing the buffer at least exponentially ensures that
 +	 * append operations are always linear in the number of
 +	 * characters appended.  Using a smaller growth rate for
 +	 * larger buffers reduces memory waste somewhat at the cost of
 +	 * a larger constant factor.
 +	 */
 +	if (as->buffer_length < 32)
 +		/* Start with a minimum 32-character buffer. */
 +		new_length = 32;
 +	else if (as->buffer_length < 8192)
 +		/* Buffers under 8k are doubled for speed. */
 +		new_length = as->buffer_length + as->buffer_length;
 +	else {
 +		/* Buffers 8k and over grow by at least 25% each time. */
 +		new_length = as->buffer_length + as->buffer_length / 4;
 +		/* Be safe: If size wraps, fail. */
 +		if (new_length < as->buffer_length) {
 +			/* On failure, wipe the string and return NULL. */
 +			archive_string_free(as);
 +			errno = ENOMEM;/* Make sure errno has ENOMEM. */
 +			return (NULL);
 +		}
 +	}
 +	/*
 +	 * The computation above is a lower limit to how much we'll
 +	 * grow the buffer.  In any case, we have to grow it enough to
 +	 * hold the request.
 +	 */
 +	if (new_length < s)
 +		new_length = s;
 +	/* Now we can reallocate the buffer. */
 +	p = (char *)realloc(as->s, new_length);
 +	if (p == NULL) {
 +		/* On failure, wipe the string and return NULL. */
 +		archive_string_free(as);
 +		errno = ENOMEM;/* Make sure errno has ENOMEM. */
 +		return (NULL);
 +	}
 +
 +	as->s = p;
 +	as->buffer_length = new_length;
 +	return (as);
 +}
 +
 +/*
 + * TODO: See if there's a way to avoid scanning
 + * the source string twice.  Then test to see
 + * if it actually helps (remember that we're almost
 + * always called with pretty short arguments, so
 + * such an optimization might not help).
 + */
 +struct archive_string *
 +archive_strncat(struct archive_string *as, const void *_p, size_t n)
 +{
 +	size_t s;
 +	const char *p, *pp;
 +
 +	p = (const char *)_p;
 +
 +	/* Like strlen(p), except won't examine positions beyond p[n]. */
 +	s = 0;
 +	pp = p;
 +	while (s < n && *pp) {
 +		pp++;
 +		s++;
 +	}
- 	return (archive_string_append(as, p, s));
++	if ((as = archive_string_append(as, p, s)) == NULL)
++		__archive_errx(1, "Out of memory");
++	return (as);
 +}
 +
 +struct archive_wstring *
 +archive_wstrncat(struct archive_wstring *as, const wchar_t *p, size_t n)
 +{
 +	size_t s;
 +	const wchar_t *pp;
 +
 +	/* Like strlen(p), except won't examine positions beyond p[n]. */
 +	s = 0;
 +	pp = p;
 +	while (s < n && *pp) {
 +		pp++;
 +		s++;
 +	}
- 	return (archive_wstring_append(as, p, s));
++	if ((as = archive_wstring_append(as, p, s)) == NULL)
++		__archive_errx(1, "Out of memory");
++	return (as);
 +}
 +
 +struct archive_string *
 +archive_strcat(struct archive_string *as, const void *p)
 +{
 +	/* strcat is just strncat without an effective limit. 
 +	 * Assert that we'll never get called with a source
 +	 * string over 16MB.
 +	 * TODO: Review all uses of strcat in the source
 +	 * and try to replace them with strncat().
 +	 */
 +	return archive_strncat(as, p, 0x1000000);
 +}
 +
 +struct archive_wstring *
 +archive_wstrcat(struct archive_wstring *as, const wchar_t *p)
 +{
 +	/* Ditto. */
 +	return archive_wstrncat(as, p, 0x1000000);
 +}
 +
 +struct archive_string *
 +archive_strappend_char(struct archive_string *as, char c)
 +{
- 	return (archive_string_append(as, &c, 1));
++	if ((as = archive_string_append(as, &c, 1)) == NULL)
++		__archive_errx(1, "Out of memory");
++	return (as);
 +}
 +
 +struct archive_wstring *
 +archive_wstrappend_wchar(struct archive_wstring *as, wchar_t c)
 +{
- 	return (archive_wstring_append(as, &c, 1));
++	if ((as = archive_wstring_append(as, &c, 1)) == NULL)
++		__archive_errx(1, "Out of memory");
++	return (as);
 +}
 +
 +/*
 + * Get the "current character set" name to use with iconv.
 + * On FreeBSD, the empty character set name "" chooses
 + * the correct character encoding for the current locale,
 + * so this isn't necessary.
 + * But iconv on Mac OS 10.6 doesn't seem to handle this correctly;
 + * on that system, we have to explicitly call nl_langinfo()
 + * to get the right name.  Not sure about other platforms.
 + *
 + * NOTE: GNU libiconv does not recognize the character-set name
 + * which some platform nl_langinfo(CODESET) returns, so we should
 + * use locale_charset() instead of nl_langinfo(CODESET) for GNU libiconv.
 + */
 +static const char *
 +default_iconv_charset(const char *charset) {
 +	if (charset != NULL && charset[0] != '\0')
 +		return charset;
 +#if HAVE_LOCALE_CHARSET && !defined(__APPLE__)
 +	/* locale_charset() is broken on Mac OS */
 +	return locale_charset();
 +#elif HAVE_NL_LANGINFO
 +	return nl_langinfo(CODESET);
 +#else
 +	return "";
 +#endif
 +}
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +
 +/*
 + * Convert MBS to WCS.
 + * Note: returns -1 if conversion fails.
 + */
 +int
 +archive_wstring_append_from_mbs(struct archive_wstring *dest,
 +    const char *p, size_t len)
 +{
 +	int r = archive_wstring_append_from_mbs_in_codepage(dest, p, len, NULL);
 +	if (r != 0 && errno == ENOMEM)
 +		__archive_errx(1, "No memory");
 +	return (r);
 +}
 +
 +static int
 +archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
 +    const char *s, size_t length, struct archive_string_conv *sc)
 +{
 +	int count, ret = 0;
 +	UINT from_cp;
 +
 +	if (sc != NULL)
 +		from_cp = sc->from_cp;
 +	else
 +		from_cp = get_current_codepage();
 +
 +	if (from_cp == CP_C_LOCALE) {
 +		/*
 +		 * "C" locale special process.
 +		 */
 +		wchar_t *ws;
 +		const unsigned char *mp;
 +
 +		if (NULL == archive_wstring_ensure(dest,
 +		    dest->length + length + 1))
 +			return (-1);
 +
 +		ws = dest->s + dest->length;
 +		mp = (const unsigned char *)s;
 +		count = 0;
 +		while (count < (int)length && *mp) {
 +			*ws++ = (wchar_t)*mp++;
 +			count++;
 +		}
 +	} else if (sc != NULL && (sc->flag & SCONV_NORMALIZATION_C)) {
 +		/*
 +		 * Normalize UTF-8 and UTF-16BE and convert it directly
 +		 * to UTF-16 as wchar_t.
 +		 */
 +		struct archive_string u16;
 +		int saved_flag = sc->flag;/* save current flag. */
 +
 +		if (is_big_endian())
 +			sc->flag |= SCONV_TO_UTF16BE;
 +		else
 +			sc->flag |= SCONV_TO_UTF16LE;
 +
 +		if (sc->flag & SCONV_FROM_UTF16) {
 +			/*
 +			 *  UTF-16BE/LE NFD ===> UTF-16 NFC
 +			 */
 +			count = utf16nbytes(s, length);
 +		} else {
 +			/*
 +			 *  UTF-8 NFD ===> UTF-16 NFC
 +			 */
 +			count = mbsnbytes(s, length);
 +		}
 +		u16.s = (char *)dest->s;
 +		u16.length = dest->length << 1;;
 +		u16.buffer_length = dest->buffer_length;
 +		ret = archive_string_normalize_C(&u16, s, count, sc);
 +		dest->s = (wchar_t *)u16.s;
 +		dest->length = u16.length >> 1;
 +		dest->buffer_length = u16.buffer_length;
 +		sc->flag = saved_flag;/* restore the saved flag. */
 +		return (ret);
 +	} else if (sc != NULL && (sc->flag & SCONV_FROM_UTF16)) {
 +		count = utf16nbytes(s, length);
 +		count >>= 1; /* to be WCS length */
 +		/* Allocate memory for WCS. */
 +		if (NULL == archive_wstring_ensure(dest,
 +		    dest->length + count + 1))
 +			return (-1);
 +		wmemcpy(dest->s + dest->length, (wchar_t *)s, count);
 +		if ((sc->flag & SCONV_FROM_UTF16BE) && !is_big_endian()) {
 +			uint16_t *u16 = (uint16_t *)(dest->s + dest->length);
 +			int b;
 +			for (b = 0; b < count; b++) {
 +				uint16_t val = archive_le16dec(u16+b);
 +				archive_be16enc(u16+b, val);
 +			}
 +		} else if ((sc->flag & SCONV_FROM_UTF16LE) && is_big_endian()) {
 +			uint16_t *u16 = (uint16_t *)(dest->s + dest->length);
 +			int b;
 +			for (b = 0; b < count; b++) {
 +				uint16_t val = archive_be16dec(u16+b);
 +				archive_le16enc(u16+b, val);
 +			}
 +		}
 +	} else {
 +		DWORD mbflag;
 +
 +		if (sc == NULL)
 +			mbflag = 0;
 +		else if (sc->flag & SCONV_FROM_CHARSET) {
 +			/* Do not trust the length which comes from
 +			 * an archive file. */
 +			length = mbsnbytes(s, length);
 +			mbflag = 0;
 +		} else
 +			mbflag = MB_PRECOMPOSED;
 +
 +		if (length == 0) {
 +			/*
 +			 * We do not need to convert any characters but make
 +			 * sure `dest' has a valid buffer(no NULL pointer).
 +			 */
 +			if (NULL == archive_wstring_ensure(dest,
 +			    dest->length + 1))
 +				return (-1);
 +			dest->s[dest->length] = L'\0';
 +			return (0);
 +		}
 +
 +		/*
 +		 * Count how many bytes are needed for WCS.
 +		 */
 +		count = MultiByteToWideChar(from_cp,
 +		    mbflag, s, length, NULL, 0);
 +		if (count == 0) {
 +			if (dest->s == NULL) {
 +				if (NULL == archive_wstring_ensure(dest,
 +				    dest->length + 1))
 +					return (-1);
 +			}
 +			dest->s[dest->length] = L'\0';
 +			return (-1);
 +		}
 +		/* Allocate memory for WCS. */
 +		if (NULL == archive_wstring_ensure(dest,
 +		    dest->length + count + 1))
 +			return (-1);
 +		/* Convert MBS to WCS. */
 +		count = MultiByteToWideChar(from_cp,
 +		    mbflag, s, length, dest->s + dest->length, count);
 +		if (count == 0)
 +			ret = -1;
 +	}
 +	dest->length += count;
 +	dest->s[dest->length] = L'\0';
 +	return (ret);
 +}
 +
 +#elif defined(HAVE_MBSNRTOWCS)
 +
 +/*
 + * Convert MBS to WCS.
 + * Note: returns -1 if conversion fails.
 + */
 +int
 +archive_wstring_append_from_mbs(struct archive_wstring *dest,
 +    const char *p, size_t len)
 +{
 +	size_t r;
 +	/*
 +	 * No single byte will be more than one wide character,
 +	 * so this length estimate will always be big enough.
 +	 */
 +	size_t wcs_length = len;
 +	size_t mbs_length = len;
 +	const char *mbs = p;
 +	wchar_t *wcs;
 +	mbstate_t shift_state;
 +
 +	memset(&shift_state, 0, sizeof(shift_state));
 +	if (NULL == archive_wstring_ensure(dest, dest->length + wcs_length + 1))
 +		__archive_errx(1,
 +		    "No memory for archive_wstring_append_from_mbs()");
 +	wcs = dest->s + dest->length;
 +	r = mbsnrtowcs(wcs, &mbs, mbs_length, wcs_length, &shift_state);
 +	if (r != (size_t)-1) {
 +		dest->length += r;
 +		dest->s[dest->length] = L'\0';
 +		return (0);
 +	}
 +	dest->s[dest->length] = L'\0';
 +	return (-1);
 +}
 +
 +#else
 +
 +/*
 + * Convert MBS to WCS.
 + * Note: returns -1 if conversion fails.
 + */
 +int
 +archive_wstring_append_from_mbs(struct archive_wstring *dest,
 +    const char *p, size_t len)
 +{
 +	size_t r;
 +	/*
 +	 * No single byte will be more than one wide character,
 +	 * so this length estimate will always be big enough.
 +	 */
 +	size_t wcs_length = len;
 +	size_t mbs_length = len;
 +	const char *mbs = p;
 +	wchar_t *wcs;
 +#if HAVE_MBRTOWC
 +	mbstate_t shift_state;
 +
 +	memset(&shift_state, 0, sizeof(shift_state));
 +#endif
 +	if (NULL == archive_wstring_ensure(dest, dest->length + wcs_length + 1))
 +		__archive_errx(1,
 +		    "No memory for archive_wstring_append_from_mbs()");
 +	wcs = dest->s + dest->length;
 +	/*
 +	 * We cannot use mbsrtowcs/mbstowcs here because those may convert
 +	 * extra MBS when strlen(p) > len and one wide character consis of
 +	 * multi bytes.
 +	 */
 +	while (wcs_length > 0 && *mbs && mbs_length > 0) {
 +#if HAVE_MBRTOWC
 +		r = mbrtowc(wcs, mbs, wcs_length, &shift_state);
 +#else
 +		r = mbtowc(wcs, mbs, wcs_length);
 +#endif
 +		if (r == (size_t)-1 || r == (size_t)-2) {
 +			dest->s[dest->length] = L'\0';
 +			return (-1);
 +		}
 +		if (r == 0 || r > mbs_length)
 +			break;
 +		wcs++;
 +		wcs_length--;
 +		mbs += r;
 +		mbs_length -= r;
 +	}
 +	dest->length = wcs - dest->s;
 +	dest->s[dest->length] = L'\0';
 +	return (0);
 +}
 +
 +#endif
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +
 +/*
 + * WCS ==> MBS.
 + * Note: returns -1 if conversion fails.
 + *
 + * Win32 builds use WideCharToMultiByte from the Windows API.
 + * (Maybe Cygwin should too?  WideCharToMultiByte will know a
 + * lot more about local character encodings than the wcrtomb()
 + * wrapper is going to know.)
 + */
 +int
 +archive_string_append_from_wcs(struct archive_string *as,
 +    const wchar_t *w, size_t len)
 +{
 +	int r = archive_string_append_from_wcs_in_codepage(as, w, len, NULL);
 +	if (r != 0 && errno == ENOMEM)
 +		__archive_errx(1, "No memory");
 +	return (r);
 +}
 +
 +static int
 +archive_string_append_from_wcs_in_codepage(struct archive_string *as,
 +    const wchar_t *ws, size_t len, struct archive_string_conv *sc)
 +{
 +	BOOL defchar_used, *dp;
 +	int count, ret = 0;
 +	UINT to_cp;
 +	int wslen = (int)len;
 +
 +	if (sc != NULL)
 +		to_cp = sc->to_cp;
 +	else
 +		to_cp = get_current_codepage();
 +
 +	if (to_cp == CP_C_LOCALE) {
 +		/*
 +		 * "C" locale special process.
 +		 */
 +		const wchar_t *wp = ws;
 +		char *p;
 +
 +		if (NULL == archive_string_ensure(as,
 +		    as->length + wslen +1))
 +			return (-1);
 +		p = as->s + as->length;
 +		count = 0;
 +		defchar_used = 0;
 +		while (count < wslen && *wp) {
 +			if (*wp > 255) {
 +				*p++ = '?';
 +				wp++;
 +				defchar_used = 1;
 +			} else
 +				*p++ = (char)*wp++;
 +			count++;
 +		}
 +	} else if (sc != NULL && (sc->flag & SCONV_TO_UTF16)) {
 +		uint16_t *u16;
 +
 +		if (NULL ==
 +		    archive_string_ensure(as, as->length + len * 2 + 2))
 +			return (-1);
 +		u16 = (uint16_t *)(as->s + as->length);
 +		count = 0;
 +		defchar_used = 0;
 +		if (sc->flag & SCONV_TO_UTF16BE) {
 +			while (count < (int)len && *ws) {
 +				archive_be16enc(u16+count, *ws);
 +				ws++;
 +				count++;
 +			}
 +		} else {
 +			while (count < (int)len && *ws) {
 +				archive_le16enc(u16+count, *ws);
 +				ws++;
 +				count++;
 +			}
 +		}
 +		count <<= 1; /* to be byte size */
 +	} else {
 +		/* Make sure the MBS buffer has plenty to set. */
 +		if (NULL ==
 +		    archive_string_ensure(as, as->length + len * 2 + 1))
 +			return (-1);
 +		do {
 +			defchar_used = 0;
 +			if (to_cp == CP_UTF8 || sc == NULL)
 +				dp = NULL;
 +			else
 +				dp = &defchar_used;
 +			count = WideCharToMultiByte(to_cp, 0, ws, wslen,
 +			    as->s + as->length, as->buffer_length-1, NULL, dp);
 +			if (count == 0 &&
 +			    GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
 +				/* Expand the MBS buffer and retry. */
 +				if (NULL == archive_string_ensure(as,
 +					as->buffer_length + len))
 +					return (-1);
 +				continue;
 +			}
 +			if (count == 0)
 +				ret = -1;
 +		} while (0);
 +	}
 +	as->length += count;
 +	as->s[as->length] = '\0';
 +	return (defchar_used?-1:ret);
 +}
 +
 +#elif defined(HAVE_WCSNRTOMBS)
 +
 +/*
 + * Translates a wide character string into current locale character set
 + * and appends to the archive_string.  Note: returns -1 if conversion
 + * fails.
 + */
 +int
 +archive_string_append_from_wcs(struct archive_string *as,
 +    const wchar_t *w, size_t len)
 +{
 +	mbstate_t shift_state;
 +	size_t r, ndest, nwc;
 +	char *dest;
 +	const wchar_t *wp, *wpp;
 +	int ret_val = 0;
 +
 +	wp = w;
 +	nwc = len;
 +	ndest = len * 2;
 +	/* Initialize the shift state. */
 +	memset(&shift_state, 0, sizeof(shift_state));
 +	while (nwc > 0) {
 +		/* Allocate buffer for MBS. */
 +		if (archive_string_ensure(as, as->length + ndest + 1) == NULL)
 +			__archive_errx(1, "Out of memory");
 +
 +		dest = as->s + as->length;
 +		wpp = wp;
 +		r = wcsnrtombs(dest, &wp, nwc,
 +		    as->buffer_length - as->length -1,
 +		    &shift_state);
 +		if (r == (size_t)-1) {
 +			if (errno == EILSEQ) {
 +				/* Retry conversion just for safe WCS. */
 +				size_t xwc = wp - wpp;
 +				wp = wpp;
 +				r = wcsnrtombs(dest, &wp, xwc,
 +				    as->buffer_length - as->length -1,
 +				    &shift_state);
 +				if (r == (size_t)-1)
 +					/* This would not happen. */
 +					return (-1);
 +				as->length += r;
 +				nwc -= wp - wpp;
 +				/* Skip an illegal wide char. */
 +				as->s[as->length++] = '?';
 +				wp++;
 +				nwc--;
 +				ret_val = -1;
 +				continue;
 +			} else {
 +				ret_val = -1;
 +				break;
 +			}
 +		}
 +		as->length += r;
 +		if (wp == NULL || (wp - wpp) >= nwc)
 +			break;
 +		/* Get a remaining WCS lenth. */
 +		nwc -= wp - wpp;
 +	}
 +	/* All wide characters are translated to MBS. */
 +	as->s[as->length] = '\0';
 +	return (ret_val);
 +}
 +
 +#elif defined(HAVE_WCTOMB) || defined(HAVE_WCRTOMB)
 +
 +/*
 + * Translates a wide character string into current locale character set
 + * and appends to the archive_string.  Note: returns -1 if conversion
 + * fails.
 + */
 +int
 +archive_string_append_from_wcs(struct archive_string *as,
 +    const wchar_t *w, size_t len)
 +{
 +	/* We cannot use the standard wcstombs() here because it
 +	 * cannot tell us how big the output buffer should be.  So
 +	 * I've built a loop around wcrtomb() or wctomb() that
 +	 * converts a character at a time and resizes the string as
 +	 * needed.  We prefer wcrtomb() when it's available because
 +	 * it's thread-safe. */
 +	int n, ret_val = 0;
 +	char *p;
 +	char *end;
 +#if HAVE_WCRTOMB
 +	mbstate_t shift_state;
 +
 +	memset(&shift_state, 0, sizeof(shift_state));
 +#else
 +	/* Clear the shift state before starting. */
 +	wctomb(NULL, L'\0');
 +#endif
 +	/*
 +	 * Allocate buffer for MBS.
 +	 * We need this allocation here since it is possible that
 +	 * as->s is still NULL.
 +	 */
 +	if (archive_string_ensure(as, as->length + len + 1) == NULL)
 +		__archive_errx(1, "Out of memory");
 +
 +	p = as->s + as->length;
 +	end = as->s + as->buffer_length - MB_CUR_MAX -1;
 +	while (*w != L'\0' && len > 0) {
 +		if (p >= end) {
 +			as->length = p - as->s;
 +			as->s[as->length] = '\0';
 +			/* Re-allocate buffer for MBS. */
 +			if (archive_string_ensure(as,
 +			    as->length + len * 2 + 1) == NULL)
 +				__archive_errx(1, "Out of memory");
 +			p = as->s + as->length;
 +			end = as->s + as->buffer_length - MB_CUR_MAX -1;
 +		}
 +#if HAVE_WCRTOMB
 +		n = wcrtomb(p, *w++, &shift_state);
 +#else
 +		n = wctomb(p, *w++);
 +#endif
 +		if (n == -1) {
 +			if (errno == EILSEQ) {
 +				/* Skip an illegal wide char. */
 +				*p++ = '?';
 +				ret_val = -1;
 +			} else {
 +				ret_val = -1;
 +				break;
 +			}
 +		} else
 +			p += n;
 +		len--;
 +	}
 +	as->length = p - as->s;
 +	as->s[as->length] = '\0';
 +	return (ret_val);
 +}
 +
 +#else /* HAVE_WCTOMB || HAVE_WCRTOMB */
 +
 +/*
 + * TODO: Test if __STDC_ISO_10646__ is defined.
 + * Non-Windows uses ISO C wcrtomb() or wctomb() to perform the conversion
 + * one character at a time.  If a non-Windows platform doesn't have
 + * either of these, fall back to the built-in UTF8 conversion.
 + */
 +int
 +archive_string_append_from_wcs(struct archive_string *as,
 +    const wchar_t *w, size_t len)
 +{
 +	(void)as;/* UNUSED */
 +	(void)w;/* UNUSED */
 +	(void)len;/* UNUSED */
 +	return (-1);
 +}
 +
 +#endif /* HAVE_WCTOMB || HAVE_WCRTOMB */
 +
 +/*
 + * Find a string conversion object by a pair of 'from' charset name
 + * and 'to' charset name from an archive object.
 + * Return NULL if not found.
 + */
 +static struct archive_string_conv *
 +find_sconv_object(struct archive *a, const char *fc, const char *tc)
 +{
 +	struct archive_string_conv *sc; 
 +
 +	if (a == NULL)
 +		return (NULL);
 +
 +	for (sc = a->sconv; sc != NULL; sc = sc->next) {
 +		if (strcmp(sc->from_charset, fc) == 0 &&
 +		    strcmp(sc->to_charset, tc) == 0)
 +			break;
 +	}
 +	return (sc);
 +}
 +
 +/*
 + * Register a string object to an archive object.
 + */
 +static void
 +add_sconv_object(struct archive *a, struct archive_string_conv *sc)
 +{
 +	struct archive_string_conv **psc; 
 +
 +	/* Add a new sconv to sconv list. */
 +	psc = &(a->sconv);
 +	while (*psc != NULL)
 +		psc = &((*psc)->next);
 +	*psc = sc;
 +}
 +
 +#if defined(__APPLE__)
 +
 +static int
 +createUniInfo(struct archive_string_conv *sconv)
 +{
 +	UnicodeMapping map;
 +	OSStatus err;
 +
 +	map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
 +	    kUnicodeNoSubset, kUnicode16BitFormat);
 +	map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
 +	    kUnicodeHFSPlusDecompVariant, kUnicode16BitFormat);
 +	map.mappingVersion = kUnicodeUseLatestMapping;
 +
 +	sconv->uniInfo = NULL;
 +	err = CreateUnicodeToTextInfo(&map, &(sconv->uniInfo));
 +	return ((err == noErr)? 0: -1);
 +}
 +
 +#endif /* __APPLE__ */
 +
 +static void
 +add_converter(struct archive_string_conv *sc, int (*converter)
 +    (struct archive_string *, const void *, size_t,
 +     struct archive_string_conv *))
 +{
 +	if (sc == NULL || sc->nconverter >= 2)
 +		__archive_errx(1, "Programing error");
 +	sc->converter[sc->nconverter++] = converter;
 +}
 +
 +static void
 +setup_converter(struct archive_string_conv *sc)
 +{
 +
 +	/* Reset. */
 +	sc->nconverter = 0;
 +
 +	/*
 +	 * Perform special sequence for the incorrect UTF-8 filenames
 +	 * made by libarchive2.x.
 +	 */
 +	if (sc->flag & SCONV_UTF8_LIBARCHIVE_2) {
 +		add_converter(sc, strncat_from_utf8_libarchive2);
 +		return;
 +	}
 +
 +	/*
 +	 * Convert a string to UTF-16BE/LE.
 +	 */
 +	if (sc->flag & SCONV_TO_UTF16) {
 +		/*
 +		 * If the current locale is UTF-8, we can translate
 +		 * a UTF-8 string into a UTF-16BE string.
 +		 */
 +		if (sc->flag & SCONV_FROM_UTF8) {
 +			add_converter(sc, archive_string_append_unicode);
 +			return;
 +		}
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +		if (sc->flag & SCONV_WIN_CP) {
 +			if (sc->flag & SCONV_TO_UTF16BE)
 +				add_converter(sc, win_strncat_to_utf16be);
 +			else
 +				add_converter(sc, win_strncat_to_utf16le);
 +			return;
 +		}
 +#endif
 +
 +#if defined(HAVE_ICONV)
 +		if (sc->cd != (iconv_t)-1) {
 +			add_converter(sc, iconv_strncat_in_locale);
 +			return;
 +		}
 +#endif
 +
 +		if (sc->flag & SCONV_BEST_EFFORT) {
 +			if (sc->flag & SCONV_TO_UTF16BE)
 +				add_converter(sc, best_effort_strncat_to_utf16be);
 +			else
 +				add_converter(sc, best_effort_strncat_to_utf16le);
 +		} else
 +			/* Make sure we have no converter. */
 +			sc->nconverter = 0;
 +		return;
 +	}
 +
 +	/*
 +	 * Convert a string from UTF-16BE/LE.
 +	 */
 +	if (sc->flag & SCONV_FROM_UTF16) {
 +		/*
 +		 * At least we should normalize a UTF-16BE string.
 +		 */
 +#if defined(__APPLE__)
 +		if (sc->flag & SCONV_NORMALIZATION_D)
 +			add_converter(sc,archive_string_normalize_D);
 +		else
 +#endif
 +		if (sc->flag & SCONV_NORMALIZATION_C)
 +			add_converter(sc, archive_string_normalize_C);
 +
 +		if (sc->flag & SCONV_TO_UTF8) {
 +			/*
 +			 * If the current locale is UTF-8, we can translate
 +			 * a UTF-16BE/LE string into a UTF-8 string directly.
 +			 */
 +			if (!(sc->flag &
 +			    (SCONV_NORMALIZATION_D |SCONV_NORMALIZATION_C)))
 +				add_converter(sc,
 +				    archive_string_append_unicode);
 +			return;
 +		}
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +		if (sc->flag & SCONV_WIN_CP) {
 +			if (sc->flag & SCONV_FROM_UTF16BE)
 +				add_converter(sc, win_strncat_from_utf16be);
 +			else
 +				add_converter(sc, win_strncat_from_utf16le);
 +			return;
 +		}
 +#endif
 +
 +#if defined(HAVE_ICONV)
 +		if (sc->cd != (iconv_t)-1) {
 +			add_converter(sc, iconv_strncat_in_locale);
 +			return;
 +		}
 +#endif
 +
 +		if ((sc->flag & (SCONV_BEST_EFFORT | SCONV_FROM_UTF16BE))
 +		    == (SCONV_BEST_EFFORT | SCONV_FROM_UTF16BE))
 +			add_converter(sc, best_effort_strncat_from_utf16be);
 +		else if ((sc->flag & (SCONV_BEST_EFFORT | SCONV_FROM_UTF16LE))
 +		    == (SCONV_BEST_EFFORT | SCONV_FROM_UTF16LE))
 +			add_converter(sc, best_effort_strncat_from_utf16le);
 +		else
 +			/* Make sure we have no converter. */
 +			sc->nconverter = 0;
 +		return;
 +	}
 +
 +	if (sc->flag & SCONV_FROM_UTF8) {
 +		/*
 +		 * At least we should normalize a UTF-8 string.
 +		 */
 +#if defined(__APPLE__)
 +		if (sc->flag & SCONV_NORMALIZATION_D)
 +			add_converter(sc,archive_string_normalize_D);
 +		else
 +#endif
 +		if (sc->flag & SCONV_NORMALIZATION_C)
 +			add_converter(sc, archive_string_normalize_C);
 +
 +		/*
 +		 * Copy UTF-8 string with a check of CESU-8.
 +		 * Apparently, iconv does not check surrogate pairs in UTF-8
 +		 * when both from-charset and to-charset are UTF-8, and then
 +		 * we use our UTF-8 copy code.
 +		 */
 +		if (sc->flag & SCONV_TO_UTF8) {
 +			/*
 +			 * If the current locale is UTF-8, we can translate
 +			 * a UTF-16BE string into a UTF-8 string directly.
 +			 */
 +			if (!(sc->flag &
 +			    (SCONV_NORMALIZATION_D |SCONV_NORMALIZATION_C)))
 +				add_converter(sc, strncat_from_utf8_to_utf8);
 +			return;
 +		}
 +	}
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +	/*
 +	 * On Windows we can use Windows API for a string conversion.
 +	 */
 +	if (sc->flag & SCONV_WIN_CP) {
 +		add_converter(sc, strncat_in_codepage);
 +		return;
 +	}
 +#endif
 +
 +#if HAVE_ICONV
 +	if (sc->cd != (iconv_t)-1) {
 +		add_converter(sc, iconv_strncat_in_locale);
 +		return;
 +	}
 +#endif
 +
 +	/*
 +	 * Try conversion in the best effort or no conversion.
 +	 */
 +	if ((sc->flag & SCONV_BEST_EFFORT) || sc->same)
 +		add_converter(sc, best_effort_strncat_in_locale);
 +	else
 +		/* Make sure we have no converter. */
 +		sc->nconverter = 0;
 +}
 +
 +/*
 + * Return canonicalized charset-name but this supports just UTF-8, UTF-16BE
 + * and CP932 which are referenced in create_sconv_object().
 + */
 +static const char *
 +canonical_charset_name(const char *charset)
 +{
 +	char cs[16];
 +	char *p;
 +	const char *s;
 +
 +	if (charset == NULL || charset[0] == '\0'
 +	    || strlen(charset) > 15)
 +		return (charset);
 +
 +	/* Copy name to uppercase. */
 +	p = cs;
 +	s = charset;
 +	while (*s) {
 +		char c = *s++;
 +		if (c >= 'a' && c <= 'z')
 +			c -= 'a' - 'A';
 +		*p++ = c;
 +	}
 +	*p++ = '\0';
 +
 +	if (strcmp(cs, "UTF-8") == 0 ||
 +	    strcmp(cs, "UTF8") == 0)
 +		return ("UTF-8");
 +	if (strcmp(cs, "UTF-16BE") == 0 ||
 +	    strcmp(cs, "UTF16BE") == 0)
 +		return ("UTF-16BE");
 +	if (strcmp(cs, "UTF-16LE") == 0 ||
 +	    strcmp(cs, "UTF16LE") == 0)
 +		return ("UTF-16LE");
 +	if (strcmp(cs, "CP932") == 0)
 +		return ("CP932");
 +	return (charset);
 +}
 +
 +/*
 + * Create a string conversion object.
 + */
 +static struct archive_string_conv *
 +create_sconv_object(const char *fc, const char *tc,
 +    unsigned current_codepage, int flag)
 +{
 +	struct archive_string_conv *sc; 
 +
 +	sc = calloc(1, sizeof(*sc));
 +	if (sc == NULL)
 +		return (NULL);
 +	sc->next = NULL;
 +	sc->from_charset = strdup(fc);
 +	if (sc->from_charset == NULL) {
 +		free(sc);
 +		return (NULL);
 +	}
 +	sc->to_charset = strdup(tc);
 +	if (sc->to_charset == NULL) {
 +		free(sc);
 +		free(sc->from_charset);
 +		return (NULL);
 +	}
 +	archive_string_init(&sc->utftmp);
 +#if defined(__APPLE__)
 +	archive_string_init(&sc->utf16nfc);
 +	archive_string_init(&sc->utf16nfd);
 +#endif
 +
 +	if (flag & SCONV_TO_CHARSET) {
 +		/*
 +		 * Convert characters from the current locale charset to
 +		 * a specified charset.
 +		 */
 +		sc->from_cp = current_codepage;
 +		sc->to_cp = make_codepage_from_charset(tc);
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +		if (IsValidCodePage(sc->to_cp))
 +			flag |= SCONV_WIN_CP;
 +#endif
 +	} else if (flag & SCONV_FROM_CHARSET) {
 +		/*
 +		 * Convert characters from a specified charset to
 +		 * the current locale charset.
 +		 */
 +		sc->to_cp = current_codepage;
 +		sc->from_cp = make_codepage_from_charset(fc);
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +		if (IsValidCodePage(sc->from_cp))
 +			flag |= SCONV_WIN_CP;
 +#endif
 +	}
 +
 +	/*
 +	 * Check if "from charset" and "to charset" are the same.
 +	 */
 +	if (strcmp(fc, tc) == 0 ||
 +	    (sc->from_cp != -1 && sc->from_cp == sc->to_cp))
 +		sc->same = 1;
 +	else
 +		sc->same = 0;
 +
 +	/*
 +	 * Mark if "from charset" or "to charset" are UTF-8 or UTF-16BE/LE.
 +	 */
 +	if (strcmp(tc, "UTF-8") == 0)
 +		flag |= SCONV_TO_UTF8;
 +	else if (strcmp(tc, "UTF-16BE") == 0)
 +		flag |= SCONV_TO_UTF16BE;
 +	else if (strcmp(tc, "UTF-16LE") == 0)
 +		flag |= SCONV_TO_UTF16LE;
 +	if (strcmp(fc, "UTF-8") == 0)
 +		flag |= SCONV_FROM_UTF8;
 +	else if (strcmp(fc, "UTF-16BE") == 0)
 +		flag |= SCONV_FROM_UTF16BE;
 +	else if (strcmp(fc, "UTF-16LE") == 0)
 +		flag |= SCONV_FROM_UTF16LE;
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +	if (sc->to_cp == CP_UTF8)
 +		flag |= SCONV_TO_UTF8;
 +	else if (sc->to_cp == CP_UTF16BE)
 +		flag |= SCONV_TO_UTF16BE | SCONV_WIN_CP;
 +	else if (sc->to_cp == CP_UTF16LE)
 +		flag |= SCONV_TO_UTF16LE | SCONV_WIN_CP;
 +	if (sc->from_cp == CP_UTF8)
 +		flag |= SCONV_FROM_UTF8;
 +	else if (sc->from_cp == CP_UTF16BE)
 +		flag |= SCONV_FROM_UTF16BE | SCONV_WIN_CP;
 +	else if (sc->from_cp == CP_UTF16LE)
 +		flag |= SCONV_FROM_UTF16LE | SCONV_WIN_CP;
 +#endif
 +
 +	/*
 +	 * Set a flag for Unicode NFD. Usually iconv cannot correctly
 +	 * handle it. So we have to translate NFD characters to NFC ones
 +	 * ourselves before iconv handles. Another reason is to prevent
 +	 * that the same sight of two filenames, one is NFC and other
 +	 * is NFD, would be in its directory.
 +	 * On Mac OS X, although its filesystem layer automatically
 +	 * convert filenames to NFD, it would be useful for filename
 +	 * comparing to find out the same filenames that we normalize
 +	 * that to be NFD ourselves.
 +	 */
 +	if ((flag & SCONV_FROM_CHARSET) &&
 +	    (flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8))) {
 +#if defined(__APPLE__)
 +		if (flag & SCONV_TO_UTF8) {
 +			if (createUniInfo(sc) == 0)
 +				flag |= SCONV_NORMALIZATION_D;
 +		} else
 +#endif
 +			flag |= SCONV_NORMALIZATION_C;
 +	}
 +
 +#if defined(HAVE_ICONV)
 +	sc->cd_w = (iconv_t)-1;
 +	/*
 +	 * Create an iconv object.
 +	 */
 +	if (((flag & (SCONV_TO_UTF8 | SCONV_TO_UTF16)) &&
 +	    (flag & (SCONV_FROM_UTF8 | SCONV_FROM_UTF16))) ||
 +	    (flag & SCONV_WIN_CP)) {
 +		/* This case we won't use iconv. */
 +		sc->cd = (iconv_t)-1;
 +#if defined(__APPLE__)
 +	} else if ((flag & SCONV_FROM_CHARSET) && (flag & SCONV_TO_UTF8)) {
 +		/*
 +		 * In case reading an archive file.
 +		 * Translate non-Unicode filenames in an archive file to
 +		 * UTF-8-MAC filenames.
 +		 */
 +		sc->cd = iconv_open("UTF-8-MAC", fc);
 +		if (sc->cd == (iconv_t)-1) {
 +			if ((sc->flag & SCONV_BEST_EFFORT) &&
 +			    strcmp(fc, "CP932") == 0) {
 +				sc->cd = iconv_open("UTF-8-MAC", "SJIS");
 +				if (sc->cd == (iconv_t)-1) {
 +					sc->cd = iconv_open(tc, fc);
 +					if (sc->cd == (iconv_t)-1)
 +						sc->cd = iconv_open(tc, "SJIS");
 +				}
 +			} else
 +				sc->cd = iconv_open(tc, fc);
 +		}
 +	} else if ((flag & SCONV_TO_CHARSET) && (flag & SCONV_FROM_UTF8)) {
 +		/*
 +		 * In case writing an archive file.
 +		 * Translate UTF-8-MAC filenames in HFS Plus to non-Unicode
 +		 * filenames.
 +		 */
 +		sc->cd = iconv_open(tc, "UTF-8-MAC");
 +		if (sc->cd == (iconv_t)-1) {
 +			if ((sc->flag & SCONV_BEST_EFFORT) &&
 +			    strcmp(tc, "CP932") == 0) {
 +				sc->cd = iconv_open("SJIS", "UTF-8-MAC");
 +				if (sc->cd == (iconv_t)-1) {
 +					sc->cd = iconv_open(tc, fc);
 +					if (sc->cd == (iconv_t)-1)
 +						sc->cd = iconv_open("SJIS", fc);
 +				}
 +			} else
 +				sc->cd = iconv_open(tc, fc);
 +		}
 +#endif
 +	} else {
 +		sc->cd = iconv_open(tc, fc);
 +		if (sc->cd == (iconv_t)-1 && (sc->flag & SCONV_BEST_EFFORT)) {
 +			/*
 +			 * Unfortunaly, all of iconv implements do support 
 +			 * "CP932" character-set, so we should use "SJIS"
 +			 * instead if iconv_open failed.
 +			 */
 +			if (strcmp(tc, "CP932") == 0)
 +				sc->cd = iconv_open("SJIS", fc);
 +			else if (strcmp(fc, "CP932") == 0)
 +				sc->cd = iconv_open(tc, "SJIS");
 +		}
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +		/*
 +		 * archive_mstring on Windows directly convert multi-bytes
 +		 * into archive_wstring in order not to depend on locale
 +		 * so that you can do a I18N programing. This will be
 +		 * used only in archive_mstring_copy_mbs_len_l so far.
 +		 */
 +		if (flag & SCONV_FROM_CHARSET) {
 +			sc->cd_w = iconv_open("UTF-8", fc);
 +			if (sc->cd_w == (iconv_t)-1 &&
 +			    (sc->flag & SCONV_BEST_EFFORT)) {
 +				if (strcmp(fc, "CP932") == 0)
 +					sc->cd_w = iconv_open("UTF-8", "SJIS");
 +			}
 +		}
 +#endif /* _WIN32 && !__CYGWIN__ */
 +	}
 +#endif	/* HAVE_ICONV */
 +
 +	sc->flag = flag;
 +
 +	/*
 +	 * Setup converters.
 +	 */
 +	setup_converter(sc);
 +
 +	return (sc);
 +}
 +
 +/*
 + * Free a string conversion object.
 + */
 +static void
 +free_sconv_object(struct archive_string_conv *sc)
 +{
 +	free(sc->from_charset);
 +	free(sc->to_charset);
 +	archive_string_free(&sc->utftmp);
 +#if HAVE_ICONV
 +	if (sc->cd != (iconv_t)-1)
 +		iconv_close(sc->cd);
 +	if (sc->cd_w != (iconv_t)-1)
 +		iconv_close(sc->cd_w);
 +#endif
 +#if defined(__APPLE__)
 +	archive_string_free(&sc->utf16nfc);
 +	archive_string_free(&sc->utf16nfd);
 +	if (sc->uniInfo != NULL)
 +		DisposeUnicodeToTextInfo(&(sc->uniInfo));
 +#endif
 +	free(sc);
 +}
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +static unsigned
 +my_atoi(const char *p)
 +{
 +	unsigned cp;
 +
 +	cp = 0;
 +	while (*p) {
 +		if (*p >= '0' && *p <= '9')
 +			cp = cp * 10 + (*p - '0');
 +		else
 +			return (-1);
 +		p++;
 +	}
 +	return (cp);
 +}
 +
 +/*
 + * Translate Charset name (as used by iconv) into CodePage (as used by Windows)
 + * Return -1 if failed.
 + *
 + * Note: This translation code may be insufficient.
 + */
 +static struct charset {
 +	const char *name;
 +	unsigned cp;
 +} charsets[] = {
 +	/* MUST BE SORTED! */
 +	{"ASCII", 1252},
 +	{"ASMO-708", 708},
 +	{"BIG5", 950},
 +	{"CHINESE", 936},
 +	{"CP367", 1252},
 +	{"CP819", 1252},
 +	{"CP1025", 21025},
 +	{"DOS-720", 720},
 +	{"DOS-862", 862},
 +	{"EUC-CN", 51936},
 +	{"EUC-JP", 51932},
 +	{"EUC-KR", 949},
 +	{"EUCCN", 51936},
 +	{"EUCJP", 51932},
 +	{"EUCKR", 949},
 +	{"GB18030", 54936},
 +	{"GB2312", 936},
 +	{"HEBREW", 1255},
 +	{"HZ-GB-2312", 52936},
 +	{"IBM273", 20273},
 +	{"IBM277", 20277},
 +	{"IBM278", 20278},
 +	{"IBM280", 20280},
 +	{"IBM284", 20284},
 +	{"IBM285", 20285},
 +	{"IBM290", 20290},
 +	{"IBM297", 20297},
 +	{"IBM367", 1252},
 +	{"IBM420", 20420},
 +	{"IBM423", 20423},
 +	{"IBM424", 20424},
 +	{"IBM819", 1252},
 +	{"IBM871", 20871},
 +	{"IBM880", 20880},
 +	{"IBM905", 20905},
 +	{"IBM924", 20924},
 +	{"ISO-8859-1", 28591},
 +	{"ISO-8859-13", 28603},
 +	{"ISO-8859-15", 28605},
 +	{"ISO-8859-2", 28592},
 +	{"ISO-8859-3", 28593},
 +	{"ISO-8859-4", 28594},
 +	{"ISO-8859-5", 28595},
 +	{"ISO-8859-6", 28596},
 +	{"ISO-8859-7", 28597},
 +	{"ISO-8859-8", 28598},
 +	{"ISO-8859-9", 28599},
 +	{"ISO8859-1", 28591},
 +	{"ISO8859-13", 28603},
 +	{"ISO8859-15", 28605},
 +	{"ISO8859-2", 28592},
 +	{"ISO8859-3", 28593},
 +	{"ISO8859-4", 28594},
 +	{"ISO8859-5", 28595},
 +	{"ISO8859-6", 28596},
 +	{"ISO8859-7", 28597},
 +	{"ISO8859-8", 28598},
 +	{"ISO8859-9", 28599},
 +	{"JOHAB", 1361},
 +	{"KOI8-R", 20866},
 +	{"KOI8-U", 21866},
 +	{"KS_C_5601-1987", 949},
 +	{"LATIN1", 1252},
 +	{"LATIN2", 28592},
 +	{"MACINTOSH", 10000},
 +	{"SHIFT-JIS", 932},
 +	{"SHIFT_JIS", 932},
 +	{"SJIS", 932},
 +	{"US", 1252},
 +	{"US-ASCII", 1252},
 +	{"UTF-16", 1200},
 +	{"UTF-16BE", 1201},
 +	{"UTF-16LE", 1200},
 +	{"UTF-8", CP_UTF8},
 +	{"X-EUROPA", 29001},
 +	{"X-MAC-ARABIC", 10004},
 +	{"X-MAC-CE", 10029},
 +	{"X-MAC-CHINESEIMP", 10008},
 +	{"X-MAC-CHINESETRAD", 10002},
 +	{"X-MAC-CROATIAN", 10082},
 +	{"X-MAC-CYRILLIC", 10007},
 +	{"X-MAC-GREEK", 10006},
 +	{"X-MAC-HEBREW", 10005},
 +	{"X-MAC-ICELANDIC", 10079},
 +	{"X-MAC-JAPANESE", 10001},
 +	{"X-MAC-KOREAN", 10003},
 +	{"X-MAC-ROMANIAN", 10010},
 +	{"X-MAC-THAI", 10021},
 +	{"X-MAC-TURKISH", 10081},
 +	{"X-MAC-UKRAINIAN", 10017},
 +};
 +static unsigned
 +make_codepage_from_charset(const char *charset)
 +{
 +	char cs[16];
 +	char *p;
 +	unsigned cp;
 +	int a, b;
 +
 +	if (charset == NULL || strlen(charset) > 15)
 +		return -1;
 +
 +	/* Copy name to uppercase. */
 +	p = cs;
 +	while (*charset) {
 +		char c = *charset++;
 +		if (c >= 'a' && c <= 'z')
 +			c -= 'a' - 'A';
 +		*p++ = c;
 +	}
 +	*p++ = '\0';
 +	cp = -1;
 +
 +	/* Look it up in the table first, so that we can easily
 +	 * override CP367, which we map to 1252 instead of 367. */
 +	a = 0;
 +	b = sizeof(charsets)/sizeof(charsets[0]);
 +	while (b > a) {
 +		int c = (b + a) / 2;
 +		int r = strcmp(charsets[c].name, cs);
 +		if (r < 0)
 +			a = c + 1;
 +		else if (r > 0)
 +			b = c;
 +		else
 +			return charsets[c].cp;
 +	}
 +
 +	/* If it's not in the table, try to parse it. */
 +	switch (*cs) {
 +	case 'C':
 +		if (cs[1] == 'P' && cs[2] >= '0' && cs[2] <= '9') {
 +			cp = my_atoi(cs + 2);
 +		} else if (strcmp(cs, "CP_ACP") == 0)
 +			cp = get_current_codepage();
 +		else if (strcmp(cs, "CP_OEMCP") == 0)
 +			cp = get_current_oemcp();
 +		break;
 +	case 'I':
 +		if (cs[1] == 'B' && cs[2] == 'M' &&
 +		    cs[3] >= '0' && cs[3] <= '9') {
 +			cp = my_atoi(cs + 3);
 +		}
 +		break;
 +	case 'W':
 +		if (strncmp(cs, "WINDOWS-", 8) == 0) {
 +			cp = my_atoi(cs + 8);
 +			if (cp != 874 && (cp < 1250 || cp > 1258))
 +				cp = -1;/* This may invalid code. */
 +		}
 +		break;
 +	}
 +	return (cp);
 +}
 +
 +/*
 + * Return ANSI Code Page of current locale set by setlocale().
 + */
 +static unsigned
 +get_current_codepage()
 +{
 +	char *locale, *p;
 +	unsigned cp;
 +
 +	locale = setlocale(LC_CTYPE, NULL);
 +	if (locale == NULL)
 +		return (GetACP());
 +	if (locale[0] == 'C' && locale[1] == '\0')
 +		return (CP_C_LOCALE);
 +	p = strrchr(locale, '.');
 +	if (p == NULL)
 +		return (GetACP());
 +	cp = my_atoi(p+1);
 +	if (cp <= 0)
 +		return (GetACP());
 +	return (cp);
 +}
 +
 +/*
 + * Translation table between Locale Name and ACP/OEMCP.
 + */
 +static struct {
 +	unsigned acp;
 +	unsigned ocp;
 +	const char *locale;
 +} acp_ocp_map[] = {
 +	{  950,  950, "Chinese_Taiwan" },
 +	{  936,  936, "Chinese_People's Republic of China" },
 +	{  950,  950, "Chinese_Taiwan" },
 +	{ 1250,  852, "Czech_Czech Republic" },
 +	{ 1252,  850, "Danish_Denmark" },
 +	{ 1252,  850, "Dutch_Netherlands" },
 +	{ 1252,  850, "Dutch_Belgium" },
 +	{ 1252,  437, "English_United States" },
 +	{ 1252,  850, "English_Australia" },
 +	{ 1252,  850, "English_Canada" },
 +	{ 1252,  850, "English_New Zealand" },
 +	{ 1252,  850, "English_United Kingdom" },
 +	{ 1252,  437, "English_United States" },
 +	{ 1252,  850, "Finnish_Finland" },
 +	{ 1252,  850, "French_France" },
 +	{ 1252,  850, "French_Belgium" },
 +	{ 1252,  850, "French_Canada" },
 +	{ 1252,  850, "French_Switzerland" },
 +	{ 1252,  850, "German_Germany" },
 +	{ 1252,  850, "German_Austria" },
 +	{ 1252,  850, "German_Switzerland" },
 +	{ 1253,  737, "Greek_Greece" },
 +	{ 1250,  852, "Hungarian_Hungary" },
 +	{ 1252,  850, "Icelandic_Iceland" },
 +	{ 1252,  850, "Italian_Italy" },
 +	{ 1252,  850, "Italian_Switzerland" },
 +	{  932,  932, "Japanese_Japan" },
 +	{  949,  949, "Korean_Korea" },
 +	{ 1252,  850, "Norwegian (BokmOl)_Norway" },
 +	{ 1252,  850, "Norwegian (BokmOl)_Norway" },
 +	{ 1252,  850, "Norwegian-Nynorsk_Norway" },
 +	{ 1250,  852, "Polish_Poland" },
 +	{ 1252,  850, "Portuguese_Portugal" },
 +	{ 1252,  850, "Portuguese_Brazil" },
 +	{ 1251,  866, "Russian_Russia" },
 +	{ 1250,  852, "Slovak_Slovakia" },
 +	{ 1252,  850, "Spanish_Spain" },
 +	{ 1252,  850, "Spanish_Mexico" },
 +	{ 1252,  850, "Spanish_Spain" },
 +	{ 1252,  850, "Swedish_Sweden" },
 +	{ 1254,  857, "Turkish_Turkey" },
 +	{ 0, 0, NULL}
 +};
 +
 +/*
 + * Return OEM Code Page of current locale set by setlocale().
 + */
 +static unsigned
 +get_current_oemcp()
 +{
 +	int i;
 +	char *locale, *p;
 +	size_t len;
 +
 +	locale = setlocale(LC_CTYPE, NULL);
 +	if (locale == NULL)
 +		return (GetOEMCP());
 +	if (locale[0] == 'C' && locale[1] == '\0')
 +		return (CP_C_LOCALE);
 +
 +	p = strrchr(locale, '.');
 +	if (p == NULL)
 +		return (GetOEMCP());
 +	len = p - locale;
 +	for (i = 0; acp_ocp_map[i].acp; i++) {
 +		if (strncmp(acp_ocp_map[i].locale, locale, len) == 0)
 +			return (acp_ocp_map[i].ocp);
 +	}
 +	return (GetOEMCP());
 +}
 +#else
 +
 +/*
 + * POSIX platform does not use CodePage.
 + */
 +
 +static unsigned
 +get_current_codepage()
 +{
 +	return (-1);/* Unknown */
 +}
 +static unsigned
 +make_codepage_from_charset(const char *charset)
 +{
 +	(void)charset; /* UNUSED */
 +	return (-1);/* Unknown */
 +}
 +static unsigned
 +get_current_oemcp()
 +{
 +	return (-1);/* Unknown */
 +}
 +
 +#endif /* defined(_WIN32) && !defined(__CYGWIN__) */
 +
 +/*
 + * Return a string conversion object.
 + */
 +static struct archive_string_conv *
 +get_sconv_object(struct archive *a, const char *fc, const char *tc, int flag)
 +{
 +	struct archive_string_conv *sc;
 +	unsigned current_codepage;
 +
 +	/* Check if we have made the sconv object. */
 +	sc = find_sconv_object(a, fc, tc);
 +	if (sc != NULL)
 +		return (sc);
 +
 +	if (a == NULL)
 +		current_codepage = get_current_codepage();
 +	else
 +		current_codepage = a->current_codepage;
 +
 +	sc = create_sconv_object(canonical_charset_name(fc),
 +	    canonical_charset_name(tc), current_codepage, flag);
 +	if (sc == NULL) {
 +		if (a != NULL)
 +			archive_set_error(a, ENOMEM,
 +			    "Could not allocate memory for "
 +			    "a string conversion object");
 +		return (NULL);
 +	}
 +
 +	/*
 +	 * If there is no converter for current string conversion object,
 +	 * we cannot handle this conversion.
 +	 */
 +	if (sc->nconverter == 0) {
 +		if (a != NULL) {
 +#if HAVE_ICONV
 +			archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +			    "iconv_open failed : Cannot handle ``%s''",
 +			    (flag & SCONV_TO_CHARSET)?tc:fc);
 +#else
 +			archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +			    "A character-set conversion not fully supported "
 +			    "on this platform");
 +#endif
 +		}
 +		/* Failed; free a sconv object. */
 +		free_sconv_object(sc);
 +		return (NULL);
 +	}
 +
 +	/*
 +	 * Success!
 +	 */
 +	if (a != NULL)
 +		add_sconv_object(a, sc);
 +	return (sc);
 +}
 +
 +static const char *
 +get_current_charset(struct archive *a)
 +{
 +	const char *cur_charset;
 +
 +	if (a == NULL)
 +		cur_charset = default_iconv_charset("");
 +	else {
 +		cur_charset = default_iconv_charset(a->current_code);
 +		if (a->current_code == NULL) {
 +			a->current_code = strdup(cur_charset);
 +			a->current_codepage = get_current_codepage();
 +			a->current_oemcp = get_current_oemcp();
 +		}
 +	}
 +	return (cur_charset);
 +}
 +
 +/*
 + * Make and Return a string conversion object.
 + * Return NULL if the platform does not support the specified conversion
 + * and best_effort is 0.
 + * If best_effort is set, A string conversion object must be returned
 + * unless memory allocation for the object fails, but the conversion
 + * might fail when non-ASCII code is found.
 + */
 +struct archive_string_conv *
 +archive_string_conversion_to_charset(struct archive *a, const char *charset,
 +    int best_effort)
 +{
 +	int flag = SCONV_TO_CHARSET;
 +
 +	if (best_effort)
 +		flag |= SCONV_BEST_EFFORT;
 +	return (get_sconv_object(a, get_current_charset(a), charset, flag));
 +}
 +
 +struct archive_string_conv *
 +archive_string_conversion_from_charset(struct archive *a, const char *charset,
 +    int best_effort)
 +{
 +	int flag = SCONV_FROM_CHARSET;
 +
 +	if (best_effort)
 +		flag |= SCONV_BEST_EFFORT;
 +	return (get_sconv_object(a, charset, get_current_charset(a), flag));
 +}
 +
 +/*
 + * archive_string_default_conversion_*_archive() are provided for Windows
 + * platform because other archiver application use CP_OEMCP for
 + * MultiByteToWideChar() and WideCharToMultiByte() for the filenames
 + * in tar or zip files. But mbstowcs/wcstombs(CRT) usually use CP_ACP
 + * unless you use setlocale(LC_ALL, ".OCP")(specify CP_OEMCP).
 + * So we should make a string conversion between CP_ACP and CP_OEMCP
 + * for compatibillty.
 + */
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +struct archive_string_conv *
 +archive_string_default_conversion_for_read(struct archive *a)
 +{
 +	const char *cur_charset = get_current_charset(a);
 +	char oemcp[16];
 +
 +	/* NOTE: a check of cur_charset is unneeded but we need
 +	 * that get_current_charset() has been surely called at
 +	 * this time whatever C compiler optimized. */
 +	if (cur_charset != NULL &&
 +	    (a->current_codepage == CP_C_LOCALE ||
 +	     a->current_codepage == a->current_oemcp))
 +		return (NULL);/* no conversion. */
 +
 +	_snprintf(oemcp, sizeof(oemcp)-1, "CP%d", a->current_oemcp);
 +	/* Make sure a null termination must be set. */
 +	oemcp[sizeof(oemcp)-1] = '\0';
 +	return (get_sconv_object(a, oemcp, cur_charset,
 +	    SCONV_FROM_CHARSET));
 +}
 +
 +struct archive_string_conv *
 +archive_string_default_conversion_for_write(struct archive *a)
 +{
 +	const char *cur_charset = get_current_charset(a);
 +	char oemcp[16];
 +
 +	/* NOTE: a check of cur_charset is unneeded but we need
 +	 * that get_current_charset() has been surely called at
 +	 * this time whatever C compiler optimized. */
 +	if (cur_charset != NULL &&
 +	    (a->current_codepage == CP_C_LOCALE ||
 +	     a->current_codepage == a->current_oemcp))
 +		return (NULL);/* no conversion. */
 +
 +	_snprintf(oemcp, sizeof(oemcp)-1, "CP%d", a->current_oemcp);
 +	/* Make sure a null termination must be set. */
 +	oemcp[sizeof(oemcp)-1] = '\0';
 +	return (get_sconv_object(a, cur_charset, oemcp,
 +	    SCONV_TO_CHARSET));
 +}
 +#else
 +struct archive_string_conv *
 +archive_string_default_conversion_for_read(struct archive *a)
 +{
 +	(void)a; /* UNUSED */
 +	return (NULL);
 +}
 +
 +struct archive_string_conv *
 +archive_string_default_conversion_for_write(struct archive *a)
 +{
 +	(void)a; /* UNUSED */
 +	return (NULL);
 +}
 +#endif
 +
 +/*
 + * Dispose of all character conversion objects in the archive object.
 + */
 +void
 +archive_string_conversion_free(struct archive *a)
 +{
 +	struct archive_string_conv *sc; 
 +	struct archive_string_conv *sc_next; 
 +
 +	for (sc = a->sconv; sc != NULL; sc = sc_next) {
 +		sc_next = sc->next;
 +		free_sconv_object(sc);
 +	}
 +	a->sconv = NULL;
 +	free(a->current_code);
 +	a->current_code = NULL;
 +}
 +
 +/*
 + * Return a conversion charset name.
 + */
 +const char *
 +archive_string_conversion_charset_name(struct archive_string_conv *sc)
 +{
 +	if (sc->flag & SCONV_TO_CHARSET)
 +		return (sc->to_charset);
 +	else
 +		return (sc->from_charset);
 +}
 +
 +/*
 + * Change the behavior of a string conversion.
 + */
 +void
 +archive_string_conversion_set_opt(struct archive_string_conv *sc, int opt)
 +{
 +	switch (opt) {
 +	/*
 +	 * A filename in UTF-8 was made with libarchive 2.x in a wrong
 +	 * assumption that wchar_t was Unicode.
 +	 * This option enables simulating the assumption in order to read
 +	 * that filname correctly.
 +	 */
 +	case SCONV_SET_OPT_UTF8_LIBARCHIVE2X:
 +#if (defined(_WIN32) && !defined(__CYGWIN__)) \
 +	 || defined(__STDC_ISO_10646__) || defined(__APPLE__)
 +		/*
 +		 * Nothing to do for it since wchar_t on these platforms
 +		 * is really Unicode.
 +		 */
 +		(void)sc; /* UNUSED */
 +#else
 +		if ((sc->flag & SCONV_UTF8_LIBARCHIVE_2) == 0) {
 +			sc->flag |= SCONV_UTF8_LIBARCHIVE_2;
 +			/* Re-setup string converters. */
 +			setup_converter(sc);
 +		}
 +#endif
 +		break;
 +	default:
 +		break;
 +	}
 +}
 +
 +/*
 + *
 + * Copy one archive_string to another in locale conversion.
 + *
 + *	archive_strncpy_in_locale();
 + *	archive_strcpy_in_locale();
 + *
 + */
 +
 +static size_t
 +mbsnbytes(const void *_p, size_t n)
 +{
 +	size_t s;
 +	const char *p, *pp;
 +
 +	if (_p == NULL)
 +		return (0);
 +	p = (const char *)_p;
 +
 +	/* Like strlen(p), except won't examine positions beyond p[n]. */
 +	s = 0;
 +	pp = p;
 +	while (s < n && *pp) {
 +		pp++;
 +		s++;
 +	}
 +	return (s);
 +}
 +
 +static size_t
 +utf16nbytes(const void *_p, size_t n)
 +{
 +	size_t s;
 +	const char *p, *pp;
 +
 +	if (_p == NULL)
 +		return (0);
 +	p = (const char *)_p;
 +
 +	/* Like strlen(p), except won't examine positions beyond p[n]. */
 +	s = 0;
 +	pp = p;
 +	n >>= 1;
 +	while (s < n && (pp[0] || pp[1])) {
 +		pp += 2;
 +		s++;
 +	}
 +	return (s<<1);
 +}
 +
 +int
 +archive_strncpy_in_locale(struct archive_string *as, const void *_p, size_t n,
 +    struct archive_string_conv *sc)
 +{
 +	as->length = 0;
 +	return (archive_strncat_in_locale(as, _p, n, sc));
 +}
 +
 +int
 +archive_strncat_in_locale(struct archive_string *as, const void *_p, size_t n,
 +    struct archive_string_conv *sc)
 +{
 +	const void *s;
 +	size_t length;
 +	int i, r = 0, r2;
 +
 +	/* We must allocate memory even if there is no data for conversion
 +	 * or copy. This simulates archive_string_append behavior. */
 +	if (_p == NULL || n == 0) {
 +		int tn = 1;
 +		if (sc != NULL && (sc->flag & SCONV_TO_UTF16))
 +			tn = 2;
 +		if (archive_string_ensure(as, as->length + tn) == NULL)
 +			return (-1);
 +		as->s[as->length] = 0;
 +		if (tn == 2)
 +			as->s[as->length+1] = 0;
 +		return (0);
 +	}
 +
 +	/*
 +	 * If sc is NULL, we just make a copy.
 +	 */
 +	if (sc == NULL) {
 +		length = mbsnbytes(_p, n);
- 		/*
- 		 * archive_string_append() will call archive_string_ensure()
- 		 * but we cannot know if that call is failed or not. so
- 		 * we call archive_string_ensure() here.
- 		 */
- 		if (archive_string_ensure(as, as->length + length + 1) == NULL)
- 			return (-1);
- 		archive_string_append(as, _p, length);
++		if (archive_string_append(as, _p, length) == NULL)
++			return (-1);/* No memory */
 +		return (0);
 +	}
 +
 +	if (sc->flag & SCONV_FROM_UTF16)
 +		length = utf16nbytes(_p, n);
 +	else
 +		length = mbsnbytes(_p, n);
 +	s = _p;
 +	i = 0;
 +	if (sc->nconverter > 1) {
 +		sc->utftmp.length = 0;
 +		r2 = sc->converter[0](&(sc->utftmp), s, length, sc);
 +		if (r2 != 0 && errno == ENOMEM)
 +			return (r2);
 +		if (r > r2)
 +			r = r2;
 +		s = sc->utftmp.s;
 +		length = sc->utftmp.length;
 +		++i;
 +	}
 +	r2 = sc->converter[i](as, s, length, sc);
 +	if (r > r2)
 +		r = r2;
 +	return (r);
 +}
 +
 +#if HAVE_ICONV
 +
 +/*
 + * Return -1 if conversion failes.
 + */
 +static int
 +iconv_strncat_in_locale(struct archive_string *as, const void *_p,
 +    size_t length, struct archive_string_conv *sc)
 +{
 +	ICONV_CONST char *inp;
 +	size_t remaining;
 +	iconv_t cd;
 +	char *outp;
 +	size_t avail, bs;
 +	int return_value = 0; /* success */
 +	int to_size, from_size;
 +
 +	if (sc->flag & SCONV_TO_UTF16)
 +		to_size = 2;
 +	else
 +		to_size = 1;
 +	if (sc->flag & SCONV_FROM_UTF16)
 +		from_size = 2;
 +	else
 +		from_size = 1;
 +
 +	if (archive_string_ensure(as, as->length + length*2+to_size) == NULL)
 +		return (-1);
 +
 +	cd = sc->cd;
 +	inp = (char *)(uintptr_t)_p;
 +	remaining = length;
 +	outp = as->s + as->length;
 +	avail = as->buffer_length - as->length - to_size;
 +	while (remaining >= (size_t)from_size) {
 +		size_t result = iconv(cd, &inp, &remaining, &outp, &avail);
 +
 +		if (result != (size_t)-1)
 +			break; /* Conversion completed. */
 +
 +		if (errno == EILSEQ || errno == EINVAL) {
 +			/*
 +		 	 * If an output charset is UTF-8 or UTF-16BE/LE,
 +			 * unknown character should be U+FFFD
 +			 * (replacement character).
 +			 */
 +			if (sc->flag & (SCONV_TO_UTF8 | SCONV_TO_UTF16)) {
 +				size_t rbytes;
 +				if (sc->flag & SCONV_TO_UTF8)
 +					rbytes = UTF8_R_CHAR_SIZE;
 +				else
 +					rbytes = 2;
 +
 +				if (avail < rbytes) {
 +					as->length = outp - as->s;
 +					bs = as->buffer_length +
 +					    (remaining * to_size) + rbytes;
 +					if (NULL ==
 +					    archive_string_ensure(as, bs))
 +						return (-1);
 +					outp = as->s + as->length;
 +					avail = as->buffer_length
 +					    - as->length - to_size;
 +				}
 +				if (sc->flag & SCONV_TO_UTF8)
 +					UTF8_SET_R_CHAR(outp);
 +				else if (sc->flag & SCONV_TO_UTF16BE)
 +					archive_be16enc(outp, UNICODE_R_CHAR);
 +				else
 +					archive_le16enc(outp, UNICODE_R_CHAR);
 +				outp += rbytes;
 +				avail -= rbytes;
 +			} else {
 +				/* Skip the illegal input bytes. */
 +				*outp++ = '?';
 +				avail--;
 +			}
 +			inp += from_size;
 +			remaining -= from_size;
 +			return_value = -1; /* failure */
 +		} else {
 +			/* E2BIG no output buffer,
 +			 * Increase an output buffer.  */
 +			as->length = outp - as->s;
 +			bs = as->buffer_length + remaining * 2;
 +			if (NULL == archive_string_ensure(as, bs))
 +				return (-1);
 +			outp = as->s + as->length;
 +			avail = as->buffer_length - as->length - to_size;
 +		}
 +	}
 +	as->length = outp - as->s;
 +	as->s[as->length] = 0;
 +	if (to_size == 2)
 +		as->s[as->length+1] = 0;
 +	return (return_value);
 +}
 +
 +#endif /* HAVE_ICONV */
 +
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +
 +/*
 + * Translate a string from a some CodePage to an another CodePage by
 + * Windows APIs, and copy the result. Return -1 if conversion failes.
 + */
 +static int
 +strncat_in_codepage(struct archive_string *as,
 +    const void *_p, size_t length, struct archive_string_conv *sc)
 +{
 +	const char *s = (const char *)_p;
 +	struct archive_wstring aws;
 +	size_t l;
 +	int r, saved_flag;
 +
 +	archive_string_init(&aws);
 +	saved_flag = sc->flag;
 +	sc->flag &= ~(SCONV_NORMALIZATION_D | SCONV_NORMALIZATION_C);
 +	r = archive_wstring_append_from_mbs_in_codepage(&aws, s, length, sc);
 +	sc->flag = saved_flag;
 +	if (r != 0) {
 +		archive_wstring_free(&aws);
 +		if (errno != ENOMEM)
 +			archive_string_append(as, s, length);
 +		return (-1);
 +	}
 +
 +	l = as->length;
 +	r = archive_string_append_from_wcs_in_codepage(
 +	    as, aws.s, aws.length, sc);
 +	if (r != 0 && errno != ENOMEM && l == as->length)
 +		archive_string_append(as, s, length);
 +	archive_wstring_free(&aws);
 +	return (r);
 +}
 +
 +/*
 + * Test whether MBS ==> WCS is okay.
 + */
 +static int
 +invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc)
 +{
 +	const char *p = (const char *)_p;
 +	unsigned codepage;
 +	DWORD mbflag = MB_ERR_INVALID_CHARS;
 +
 +	if (sc->flag & SCONV_FROM_CHARSET)
 +		codepage = sc->to_cp;
 +	else
 +		codepage = sc->from_cp;
 +
 +	if (codepage == CP_C_LOCALE)
 +		return (0);
 +	if (codepage != CP_UTF8)
 +		mbflag |= MB_PRECOMPOSED;
 +
 +	if (MultiByteToWideChar(codepage, mbflag, p, n, NULL, 0) == 0)
 +		return (-1); /* Invalid */
 +	return (0); /* Okay */
 +}
 +
 +#else
 +
 +/*
 + * Test whether MBS ==> WCS is okay.
 + */
 +static int
 +invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc)
 +{
 +	const char *p = (const char *)_p;
 +	size_t r;
 +
 +#if HAVE_MBRTOWC
 +	mbstate_t shift_state;
 +
 +	memset(&shift_state, 0, sizeof(shift_state));
 +#else
 +	/* Clear the shift state before starting. */
 +	mbtowc(NULL, NULL, 0);
 +#endif
 +	while (n) {
 +		wchar_t wc;
 +
 +#if HAVE_MBRTOWC
 +		r = mbrtowc(&wc, p, n, &shift_state);
 +#else
 +		r = mbtowc(&wc, p, n);
 +#endif
 +		if (r == (size_t)-1 || r == (size_t)-2)
 +			return (-1);/* Invalid. */
 +		if (r == 0)
 +			break;
 +		p += r;
 +		n -= r;
 +	}
 +	(void)sc; /* UNUSED */
 +	return (0); /* All Okey. */
 +}
 +
 +#endif /* defined(_WIN32) && !defined(__CYGWIN__) */
 +
 +/*
 + * Basically returns -1 because we cannot make a conversion of charset
 + * without iconv but in some cases this would return 0.
 + * Returns 0 if all copied characters are ASCII.
 + * Returns 0 if both from-locale and to-locale are the same and those
 + * can be WCS with no error.
 + */
 +static int
 +best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
 +    size_t length, struct archive_string_conv *sc)
 +{
 +	size_t remaining;
 +	char *outp;
 +	const char *inp;
 +	size_t avail;
 +	int return_value = 0; /* success */
 +
 +	/*
 +	 * If both from-locale and to-locale is the same, this makes a copy.
 +	 * And then this checks all copied MBS can be WCS if so returns 0.
 +	 */
 +	if (sc->same) {
- 		archive_string_append(as, _p, length);
++		if (archive_string_append(as, _p, length) == NULL)
++			return (-1);/* No memory */
 +		return (invalid_mbs(_p, length, sc));
 +	}
 +
 +	/*
 +	 * If a character is ASCII, this just copies it. If not, this
 +	 * assigns '?' charater instead but in UTF-8 locale this assigns
 +	 * byte sequence 0xEF 0xBD 0xBD, which are code point U+FFFD,
 +	 * a Replacement Character in Unicode.
 +	 */
 +	if (archive_string_ensure(as, as->length + length + 1) == NULL)
 +		return (-1);
 +
 +	remaining = length;
 +	inp = (const char *)_p;
 +	outp = as->s + as->length;
 +	avail = as->buffer_length - as->length -1;
 +	while (*inp && remaining > 0) {
 +		if (*inp < 0 && (sc->flag & SCONV_TO_UTF8)) {
 +			if (avail < UTF8_R_CHAR_SIZE) {
 +				as->length = outp - as->s;
 +				if (NULL == archive_string_ensure(as,
 +				    as->buffer_length + remaining +
 +				    UTF8_R_CHAR_SIZE))
 +					return (-1);
 +				outp = as->s + as->length;
 +				avail = as->buffer_length - as->length -1;
 +			}
 +			/*
 +		 	 * When coping a string in UTF-8, unknown character
 +			 * should be U+FFFD (replacement character).
 +			 */
 +			UTF8_SET_R_CHAR(outp);
 +			outp += UTF8_R_CHAR_SIZE;
 +			avail -= UTF8_R_CHAR_SIZE;
 +			inp++;
 +			remaining--;
 +			return_value = -1;
 +		} else if (*inp < 0) {
 +			*outp++ = '?';
 +			inp++;
 +			remaining--;
 +			return_value = -1;
 +		} else {
 +			*outp++ = *inp++;
 +			remaining--;
 +		}
 +	}
 +	as->length = outp - as->s;
 +	as->s[as->length] = '\0';
 +	return (return_value);
 +}
 +
 +
 +/*
 + * Unicode conversion functions.
 + *   - UTF-8 <===> UTF-8 in removing surrogate pairs.
 + *   - UTF-8 NFD ===> UTF-8 NFC in removing surrogate pairs.
 + *   - UTF-8 made by libarchive 2.x ===> UTF-8.
 + *   - UTF-16BE <===> UTF-8.
 + *
 + */
 +
 +/*
 + * Utility to convert a single UTF-8 sequence.
 + *
 + * Usually return used bytes, return used byte in negative value when
 + * a unicode character is replaced with U+FFFD.
 + * See also http://unicode.org/review/pr-121.html Public Review Issue #121
 + * Recommended Practice for Replacement Characters.
 + */
 +static int
 +_utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
 +{
 +	static const char utf8_count[256] = {
 +		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */
 +		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 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, 1,/* 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, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */
 +		 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */
 +		 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */
 +		 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */
 +	};
 +	int ch, i;
 +	int cnt;
 +	uint32_t wc;
 +
 +	/* Sanity check. */
 +	if (n == 0)
 +		return (0);
 +	/*
 +	 * Decode 1-4 bytes depending on the value of the first byte.
 +	 */
 +	ch = (unsigned char)*s;
 +	if (ch == 0)
 +		return (0); /* Standard:  return 0 for end-of-string. */
 +	cnt = utf8_count[ch];
 +
 +	/* Invalide sequence or there are not plenty bytes. */
 +	if ((int)n < cnt) {
 +		cnt = n;
 +		for (i = 1; i < cnt; i++) {
 +			if ((s[i] & 0xc0) != 0x80) {
 +				cnt = i;
 +				break;
 +			}
 +		}
 +		goto invalid_sequence;
 +	}
 +
 +	/* Make a Unicode code point from a single UTF-8 sequence. */
 +	switch (cnt) {
 +	case 1:	/* 1 byte sequence. */
 +		*pwc = ch & 0x7f;
 +		return (cnt);
 +	case 2:	/* 2 bytes sequence. */
 +		if ((s[1] & 0xc0) != 0x80) {
 +			cnt = 1;
 +			goto invalid_sequence;
 +		}
 +		*pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f);
 +		return (cnt);
 +	case 3:	/* 3 bytes sequence. */
 +		if ((s[1] & 0xc0) != 0x80) {
 +			cnt = 1;
 +			goto invalid_sequence;
 +		}
 +		if ((s[2] & 0xc0) != 0x80) {
 +			cnt = 2;
 +			goto invalid_sequence;
 +		}
 +		wc = ((ch & 0x0f) << 12)
 +		    | ((s[1] & 0x3f) << 6)
 +		    | (s[2] & 0x3f);
 +		if (wc < 0x800)
 +			goto invalid_sequence;/* Overlong sequence. */
 +		break;
 +	case 4:	/* 4 bytes sequence. */
 +		if ((s[1] & 0xc0) != 0x80) {
 +			cnt = 1;
 +			goto invalid_sequence;
 +		}
 +		if ((s[2] & 0xc0) != 0x80) {
 +			cnt = 2;
 +			goto invalid_sequence;
 +		}
 +		if ((s[3] & 0xc0) != 0x80) {
 +			cnt = 3;
 +			goto invalid_sequence;
 +		}
 +		wc = ((ch & 0x07) << 18)
 +		    | ((s[1] & 0x3f) << 12)
 +		    | ((s[2] & 0x3f) << 6)
 +		    | (s[3] & 0x3f);
 +		if (wc < 0x10000)
 +			goto invalid_sequence;/* Overlong sequence. */
 +		break;
 +	default: /* Others are all invalid sequence. */
 +		if (ch == 0xc0 || ch == 0xc1)
 +			cnt = 2;
 +		else if (ch >= 0xf5 && ch <= 0xf7)
 +			cnt = 4;
 +		else if (ch >= 0xf8 && ch <= 0xfb)
 +			cnt = 5;
 +		else if (ch == 0xfc || ch == 0xfd)
 +			cnt = 6;
 +		else
 +			cnt = 1;
 +		if ((int)n < cnt)
 +			cnt = n;
 +		for (i = 1; i < cnt; i++) {
 +			if ((s[i] & 0xc0) != 0x80) {
 +				cnt = i;
 +				break;
 +			}
 +		}
 +		goto invalid_sequence;
 +	}
 +
 +	/* The code point larger than 0x10FFFF is not leagal
 +	 * Unicode values. */
 +	if (wc > UNICODE_MAX)
 +		goto invalid_sequence;
 +	/* Correctly gets a Unicode, returns used bytes. */
 +	*pwc = wc;
 +	return (cnt);
 +invalid_sequence:
 +	*pwc = UNICODE_R_CHAR;/* set the Replacement Character instead. */
 +	return (cnt * -1);
 +}
 +
 +static int
 +utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
 +{
 +	int cnt;
 +
 +	cnt = _utf8_to_unicode(pwc, s, n);
 +	/* Any of Surrogate pair is not leagal Unicode values. */
 +	if (cnt == 3 && IS_SURROGATE_PAIR_LA(*pwc))
 +		return (-3);
 +	return (cnt);
 +}
 +
 +static inline uint32_t
 +combine_surrogate_pair(uint32_t uc, uint32_t uc2)
 +{
 +	uc -= 0xD800;
 +	uc *= 0x400;
 +	uc += uc2 - 0xDC00;
 +	uc += 0x10000;
 +	return (uc);
 +}
 +
 +/*
 + * Convert a single UTF-8/CESU-8 sequence to a Unicode code point in
 + * removing surrogate pairs.
 + *
 + * CESU-8: The Compatibility Encoding Scheme for UTF-16.
 + *
 + * Usually return used bytes, return used byte in negative value when
 + * a unicode character is replaced with U+FFFD.
 + */
 +static int
 +cesu8_to_unicode(uint32_t *pwc, const char *s, size_t n)
 +{
 +	uint32_t wc, wc2;
 +	int cnt;
 +
 +	cnt = _utf8_to_unicode(&wc, s, n);
 +	if (cnt == 3 && IS_HIGH_SURROGATE_LA(wc)) {
 +		if (n - 3 < 3) {
 +			/* Invalid byte sequence. */
 +			goto invalid_sequence;
 +		}
 +		cnt = _utf8_to_unicode(&wc2, s+3, n-3);
 +		if (cnt != 3 || !IS_LOW_SURROGATE_LA(wc2)) {
 +			/* Invalid byte sequence. */
 +			goto invalid_sequence;
 +		}
 +		wc = combine_surrogate_pair(wc, wc2);
 +		cnt = 6;
 +	} else if (cnt == 3 && IS_LOW_SURROGATE_LA(wc)) {
 +		/* Invalid byte sequence. */
 +		goto invalid_sequence;
 +	}
 +	*pwc = wc;
 +	return (cnt);
 +invalid_sequence:
 +	*pwc = UNICODE_R_CHAR;/* set the Replacement Character instead. */
 +	if (cnt > 0)
 +		cnt *= -1;
 +	return (cnt);
 +}
 +
 +/*
 + * Convert a Unicode code point to a single UTF-8 sequence.
 + *
 + * NOTE:This function does not check if the Unicode is leagal or not.
 + * Please you definitely check it before calling this.
 + */
 +static size_t
 +unicode_to_utf8(char *p, size_t remaining, uint32_t uc)
 +{
 +	char *_p = p;
 +
 +	/* Translate code point to UTF8 */
 +	if (uc <= 0x7f) {
 +		if (remaining == 0)
 +			return (0);
 +		*p++ = (char)uc;
 +	} else if (uc <= 0x7ff) {
 +		if (remaining < 2)
 +			return (0);
 +		*p++ = 0xc0 | ((uc >> 6) & 0x1f);
 +		*p++ = 0x80 | (uc & 0x3f);
 +	} else if (uc <= 0xffff) {
 +		if (remaining < 3)
 +			return (0);
 +		*p++ = 0xe0 | ((uc >> 12) & 0x0f);
 +		*p++ = 0x80 | ((uc >> 6) & 0x3f);
 +		*p++ = 0x80 | (uc & 0x3f);
 +	} else if (uc <= UNICODE_MAX) {
 +		if (remaining < 4)
 +			return (0);
 +		*p++ = 0xf0 | ((uc >> 18) & 0x07);
 +		*p++ = 0x80 | ((uc >> 12) & 0x3f);
 +		*p++ = 0x80 | ((uc >> 6) & 0x3f);
 +		*p++ = 0x80 | (uc & 0x3f);
 +	} else {
 +		/*
 +		 * Undescribed code point should be U+FFFD
 +		 * (replacement character).
 +		 */
 +		if (remaining < UTF8_R_CHAR_SIZE)
 +			return (0);
 +		UTF8_SET_R_CHAR(p);
 +		p += UTF8_R_CHAR_SIZE;
 +	}
 +	return (p - _p);
 +}
 +
 +static int
 +utf16be_to_unicode(uint32_t *pwc, const char *s, size_t n)
 +{
 +	return (utf16_to_unicode(pwc, s, n, 1));
 +}
 +
 +static int
 +utf16le_to_unicode(uint32_t *pwc, const char *s, size_t n)
 +{
 +	return (utf16_to_unicode(pwc, s, n, 0));
 +}
 +
 +static int
 +utf16_to_unicode(uint32_t *pwc, const char *s, size_t n, int be)
 +{
 +	const char *utf16 = s;
 +	unsigned uc;
 +
 +	if (n == 0)
 +		return (0);
 +	if (n == 1) {
 +		/* set the Replacement Character instead. */
 +		*pwc = UNICODE_R_CHAR;
 +		return (-1);
 +	}
 +
 +	if (be)
 +		uc = archive_be16dec(utf16);
 +	else
 +		uc = archive_le16dec(utf16);
 +	utf16 += 2;
 +		
 +	/* If this is a surrogate pair, assemble the full code point.*/
 +	if (IS_HIGH_SURROGATE_LA(uc)) {
 +		unsigned uc2;
 +
 +		if (n >= 4) {
 +			if (be)
 +				uc2 = archive_be16dec(utf16);
 +			else
 +				uc2 = archive_le16dec(utf16);
 +		} else
 +			uc2 = 0;
 +		if (IS_LOW_SURROGATE_LA(uc2)) {
 +			uc = combine_surrogate_pair(uc, uc2);
 +			utf16 += 2;
 +		} else {
 +	 		/* Undescribed code point should be U+FFFD
 +		 	* (replacement character). */
 +			*pwc = UNICODE_R_CHAR;
 +			return (-2);
 +		}
 +	}
 +
 +	/*
 +	 * Surrogate pair values(0xd800 through 0xdfff) are only
 +	 * used by UTF-16, so, after above culculation, the code
 +	 * must not be surrogate values, and Unicode has no codes
 +	 * larger than 0x10ffff. Thus, those are not leagal Unicode
 +	 * values.
 +	 */
 +	if (IS_SURROGATE_PAIR_LA(uc) || uc > UNICODE_MAX) {
 +	 	/* Undescribed code point should be U+FFFD
 +	 	* (replacement character). */
 +		*pwc = UNICODE_R_CHAR;
 +		return (((int)(utf16 - s)) * -1);
 +	}
 +	*pwc = uc;
 +	return ((int)(utf16 - s));
 +}
 +
 +static size_t
 +unicode_to_utf16be(char *p, size_t remaining, uint32_t uc)
 +{
 +	char *utf16 = p;
 +
 +	if (uc > 0xffff) {
 +		/* We have a code point that won't fit into a
 +		 * wchar_t; convert it to a surrogate pair. */
 +		if (remaining < 4)
 +			return (0);
 +		uc -= 0x10000;
 +		archive_be16enc(utf16, ((uc >> 10) & 0x3ff) + 0xD800);
 +		archive_be16enc(utf16+2, (uc & 0x3ff) + 0xDC00);
 +		return (4);
 +	} else {
 +		if (remaining < 2)
 +			return (0);
 +		archive_be16enc(utf16, uc);
 +		return (2);
 +	}
 +}
 +
 +static size_t
 +unicode_to_utf16le(char *p, size_t remaining, uint32_t uc)
 +{
 +	char *utf16 = p;
 +
 +	if (uc > 0xffff) {
 +		/* We have a code point that won't fit into a
 +		 * wchar_t; convert it to a surrogate pair. */
 +		if (remaining < 4)
 +			return (0);
 +		uc -= 0x10000;
 +		archive_le16enc(utf16, ((uc >> 10) & 0x3ff) + 0xD800);
 +		archive_le16enc(utf16+2, (uc & 0x3ff) + 0xDC00);
 +		return (4);
 +	} else {
 +		if (remaining < 2)
 +			return (0);
 +		archive_le16enc(utf16, uc);
 +		return (2);
 +	}
 +}
 +
 +/*
 + * Copy UTF-8 string in checking surrogate pair.
 + * If any surrogate pair are found, it would be canonicalized.
 + */
 +static int
 +strncat_from_utf8_to_utf8(struct archive_string *as, const void *_p, size_t len,
 +    struct archive_string_conv *sc)
 +{
 +	const char *s;
 +	char *p, *endp;
 +	int n, ret = 0;
 +
 +	(void)sc; /* UNUSED */
 +
 +	if (archive_string_ensure(as, as->length + len + 1) == NULL)
 +		return (-1);
 +
 +	s = (const char *)_p;
 +	p = as->s + as->length;
 +	endp = as->s + as->buffer_length -1;
 +	do {
 +		uint32_t uc;
 +		const char *ss = s;
 +		size_t w;
 +
 +		/*
 +		 * Forward byte sequence until a conversion of that is needed.
 +		 */
 +		while ((n = utf8_to_unicode(&uc, s, len)) > 0) {
 +			s += n;
 +			len -= n;
 +		}
 +		if (ss < s) {
 +			if (p + (s - ss) > endp) {
 +				as->length = p - as->s;
 +				if (archive_string_ensure(as,
 +				    as->buffer_length + len + 1) == NULL)
 +					return (-1);
 +				p = as->s + as->length;
 +				endp = as->s + as->buffer_length -1;
 +			}
 +
 +			memcpy(p, ss, s - ss);
 +			p += s - ss;
 +		}
 +
 +		/*
 +		 * If n is negative, current byte sequence needs a replacement.
 +		 */
 +		if (n < 0) {
 +			if (n == -3 && IS_SURROGATE_PAIR_LA(uc)) {
 +				/* Current byte sequence may be CESU-8. */
 +				n = cesu8_to_unicode(&uc, s, len);
 +			}
 +			if (n < 0) {
 +				ret = -1;
 +				n *= -1;/* Use a replaced unicode character. */
 +			}
 +
 +			/* Rebuild UTF-8 byte sequence. */
 +			while ((w = unicode_to_utf8(p, endp - p, uc)) == 0) {
 +				as->length = p - as->s;
 +				if (archive_string_ensure(as,
 +				    as->buffer_length + len + 1) == NULL)
 +					return (-1);
 +				p = as->s + as->length;
 +				endp = as->s + as->buffer_length -1;
 +			}
 +			p += w;
 +			s += n;
 +			len -= n;
 +		}
 +	} while (n > 0);
 +	as->length = p - as->s;
 +	as->s[as->length] = '\0';
 +	return (ret);
 +}
 +
 +static int
 +archive_string_append_unicode(struct archive_string *as, const void *_p,
 +    size_t len, struct archive_string_conv *sc)
 +{
 +	const char *s;
 +	char *p, *endp;
 +	uint32_t uc;
 +	size_t w;
 +	int n, ret = 0, ts, tm;
 +	int (*parse)(uint32_t *, const char *, size_t);
 +	size_t (*unparse)(char *, size_t, uint32_t);
 +
 +	if (sc->flag & SCONV_TO_UTF16BE) {
 +		unparse = unicode_to_utf16be;
 +		ts = 2;
 +	} else if (sc->flag & SCONV_TO_UTF16LE) {
 +		unparse = unicode_to_utf16le;
 +		ts = 2;
 +	} else if (sc->flag & SCONV_TO_UTF8) {
 +		unparse = unicode_to_utf8;
 +		ts = 1;
 +	} else {
 +		/*
 +		 * This case is going to be converted to another
 +		 * character-set through iconv.
 +		 */
 +		if (sc->flag & SCONV_FROM_UTF16BE) {
 +			unparse = unicode_to_utf16be;
 +			ts = 2;
 +		} else if (sc->flag & SCONV_FROM_UTF16LE) {
 +			unparse = unicode_to_utf16le;
 +			ts = 2;
 +		} else {
 +			unparse = unicode_to_utf8;
 +			ts = 1;
 +		}
 +	}
 +
 +	if (sc->flag & SCONV_FROM_UTF16BE) {
 +		parse = utf16be_to_unicode;
 +		tm = 1;
 +	} else if (sc->flag & SCONV_FROM_UTF16LE) {
 +		parse = utf16le_to_unicode;
 +		tm = 1;
 +	} else {
 +		parse = cesu8_to_unicode;
 +		tm = ts;
 +	}
 +
 +	if (archive_string_ensure(as, as->length + len * tm + ts) == NULL)
 +		return (-1);
 +
 +	s = (const char *)_p;
 +	p = as->s + as->length;
 +	endp = as->s + as->buffer_length - ts;
 +	while ((n = parse(&uc, s, len)) != 0) {
 +		if (n < 0) {
 +			/* Use a replaced unicode character. */
 +			n *= -1;
 +			ret = -1;
 +		}
 +		s += n;
 +		len -= n;
 +		while ((w = unparse(p, endp - p, uc)) == 0) {
 +			/* There is not enough output buffer so
 +			 * we have to expand it. */
 +			as->length = p - as->s;
 +			if (archive_string_ensure(as,
 +			    as->buffer_length + len * tm + ts) == NULL)
 +				return (-1);
 +			p = as->s + as->length;
 +			endp = as->s + as->buffer_length - ts;
 +		}
 +		p += w;
 +	}
 +	as->length = p - as->s;
 +	as->s[as->length] = '\0';
 +	if (ts == 2)
 +		as->s[as->length+1] = '\0';
 +	return (ret);
 +}
 +
 +/*
 + * Following Constants for Hangul compositions this information comes from
 + * Unicode Standard Annex #15  http://unicode.org/reports/tr15/
 + */
 +#define HC_SBASE	0xAC00
 +#define HC_LBASE	0x1100
 +#define HC_VBASE	0x1161
 +#define HC_TBASE	0x11A7
 +#define HC_LCOUNT	19
 +#define HC_VCOUNT	21
 +#define HC_TCOUNT	28
 +#define HC_NCOUNT	(HC_VCOUNT * HC_TCOUNT)
 +#define HC_SCOUNT	(HC_LCOUNT * HC_NCOUNT)
 +
 +static uint32_t
 +get_nfc(uint32_t uc, uint32_t uc2)
 +{
 +	int t, b;
 +
 +	t = 0;
 +	b = sizeof(u_composition_table)/sizeof(u_composition_table[0]) -1;
 +	while (b >= t) {
 +		int m = (t + b) / 2;
 +		if (u_composition_table[m].cp1 < uc)
 +			t = m + 1;
 +		else if (u_composition_table[m].cp1 > uc)
 +			b = m - 1;
 +		else if (u_composition_table[m].cp2 < uc2)
 +			t = m + 1;
 +		else if (u_composition_table[m].cp2 > uc2)
 +			b = m - 1;
 +		else
 +			return (u_composition_table[m].nfc);
 +	}
 +	return (0);
 +}
 +
 +#define FDC_MAX 10	/* The maximum number of Following Decomposable
 +			 * Characters. */
 +
 +/*
 + * Update first code point.
 + */
 +#define UPDATE_UC(new_uc)	do {		\
 +	uc = new_uc;				\
 +	ucptr = NULL;				\
 +} while (0)
 +
 +/*
 + * Replace first code point with second code point.
 + */
 +#define REPLACE_UC_WITH_UC2() do {		\
 +	uc = uc2;				\
 +	ucptr = uc2ptr;				\
 +	n = n2;					\
 +} while (0)
 +
 +#define EXPAND_BUFFER() do {			\
 +	as->length = p - as->s;			\
 +	if (archive_string_ensure(as,		\
 +	    as->buffer_length + len * tm + ts) == NULL)\
 +		return (-1);			\
 +	p = as->s + as->length;			\
 +	endp = as->s + as->buffer_length - ts;	\
 +} while (0)
 +
 +#define UNPARSE(p, endp, uc)	do {		\
 +	while ((w = unparse(p, (endp) - (p), uc)) == 0) {\
 +		EXPAND_BUFFER();		\
 +	}					\
 +	p += w;					\
 +} while (0)
 +
 +/*
 + * Write first code point.
 + * If the code point has not be changed from its original code,
 + * this just copies it from its original buffer pointer.
 + * If not, this converts it to UTF-8 byte sequence and copies it.
 + */
 +#define WRITE_UC()	do {			\
 +	if (ucptr) {				\
 +		if (p + n > endp)		\
 +			EXPAND_BUFFER();	\
 +		switch (n) {			\
 +		case 4:				\
 +			*p++ = *ucptr++;	\
 +			/* FALL THROUGH */	\
 +		case 3:				\
 +			*p++ = *ucptr++;	\
 +			/* FALL THROUGH */	\
 +		case 2:				\
 +			*p++ = *ucptr++;	\
 +			/* FALL THROUGH */	\
 +		case 1:				\
 +			*p++ = *ucptr;		\
 +			break;			\
 +		}				\
 +		ucptr = NULL;			\
 +	} else {				\
 +		UNPARSE(p, endp, uc);		\
 +	}					\
 +} while (0)
 +
 +/*
 + * Collect following decomposable code points.
 + */
 +#define COLLECT_CPS(start)	do {		\
 +	int _i;					\
 +	for (_i = start; _i < FDC_MAX ; _i++) {	\
 +		nx = parse(&ucx[_i], s, len);	\
 +		if (nx <= 0)			\
 +			break;			\
 +		cx = CCC(ucx[_i]);		\
 +		if (cl >= cx && cl != 228 && cx != 228)\
 +			break;			\
 +		s += nx;			\
 +		len -= nx;			\
 +		cl = cx;			\
 +		ccx[_i] = cx;			\
 +	}					\
 +	if (_i >= FDC_MAX) {			\
 +		ret = -1;			\
 +		ucx_size = FDC_MAX;		\
 +	} else					\
 +		ucx_size = _i;			\
 +} while (0)
 +
 +/*
 + * Normalize UTF-8/UTF-16BE characters to Form C and copy the result.
 + *
 + * TODO: Convert composition exclusions,which are never converted
 + * from NFC,NFD,NFKC and NFKD, to Form C.
 + */
 +static int
 +archive_string_normalize_C(struct archive_string *as, const void *_p,
 +    size_t len, struct archive_string_conv *sc)
 +{
 +	const char *s = (const char *)_p;
 +	char *p, *endp;
 +	uint32_t uc, uc2;
 +	size_t w;
 +	int always_replace, n, n2, ret = 0, spair, ts, tm;
 +	int (*parse)(uint32_t *, const char *, size_t);
 +	size_t (*unparse)(char *, size_t, uint32_t);
 +
 +	always_replace = 1;
 +	ts = 1;/* text size. */
 +	if (sc->flag & SCONV_TO_UTF16BE) {
 +		unparse = unicode_to_utf16be;
 +		ts = 2;
 +		if (sc->flag & SCONV_FROM_UTF16BE)
 +			always_replace = 0;
 +	} else if (sc->flag & SCONV_TO_UTF16LE) {
 +		unparse = unicode_to_utf16le;
 +		ts = 2;
 +		if (sc->flag & SCONV_FROM_UTF16LE)
 +			always_replace = 0;
 +	} else if (sc->flag & SCONV_TO_UTF8) {
 +		unparse = unicode_to_utf8;
 +		if (sc->flag & SCONV_FROM_UTF8)
 +			always_replace = 0;
 +	} else {
 +		/*
 +		 * This case is going to be converted to another
 +		 * character-set through iconv.
 +		 */
 +		always_replace = 0;
 +		if (sc->flag & SCONV_FROM_UTF16BE) {
 +			unparse = unicode_to_utf16be;
 +			ts = 2;
 +		} else if (sc->flag & SCONV_FROM_UTF16LE) {
 +			unparse = unicode_to_utf16le;
 +			ts = 2;
 +		} else {
 +			unparse = unicode_to_utf8;
 +		}
 +	}
 +
 +	if (sc->flag & SCONV_FROM_UTF16BE) {
 +		parse = utf16be_to_unicode;
 +		tm = 1;
 +		spair = 4;/* surrogate pair size in UTF-16. */
 +	} else if (sc->flag & SCONV_FROM_UTF16LE) {
 +		parse = utf16le_to_unicode;
 +		tm = 1;
 +		spair = 4;/* surrogate pair size in UTF-16. */
 +	} else {
 +		parse = cesu8_to_unicode;
 +		tm = ts;
 +		spair = 6;/* surrogate pair size in UTF-8. */
 +	}
 +
 +	if (archive_string_ensure(as, as->length + len * tm + ts) == NULL)
 +		return (-1);
 +
 +	p = as->s + as->length;
 +	endp = as->s + as->buffer_length - ts;
 +	while ((n = parse(&uc, s, len)) != 0) {
 +		const char *ucptr, *uc2ptr;
 +
 +		if (n < 0) {
 +			/* Use a replaced unicode character. */
 +			UNPARSE(p, endp, uc);
 +			s += n*-1;
 +			len -= n*-1;
 +			ret = -1;
 +			continue;
 +		} else if (n == spair || always_replace)
 +			/* uc is converted from a surrogate pair.
 +			 * this should be treated as a changed code. */
 +			ucptr = NULL;
 +		else
 +			ucptr = s;
 +		s += n;
 +		len -= n;
 +
 +		/* Read second code point. */
 +		while ((n2 = parse(&uc2, s, len)) > 0) {
 +			uint32_t ucx[FDC_MAX];
 +			int ccx[FDC_MAX];
 +			int cl, cx, i, nx, ucx_size;
 +			int LIndex,SIndex;
 +			uint32_t nfc;
 +
 +			if (n2 == spair || always_replace)
 +				/* uc2 is converted from a surrogate pair.
 +			 	 * this should be treated as a changed code. */
 +				uc2ptr = NULL;
 +			else
 +				uc2ptr = s;
 +			s += n2;
 +			len -= n2;
 +
 +			/*
 +			 * If current second code point is out of decomposable
 +			 * code points, finding compositions is unneeded.
 +			 */
 +			if (!IS_DECOMPOSABLE_BLOCK(uc2)) {
 +				WRITE_UC();
 +				REPLACE_UC_WITH_UC2();
 +				continue;
 +			}
 +
 +			/*
 +			 * Try to combine current code points.
 +			 */
 +			/*
 +			 * We have to combine Hangul characters according to
 +			 * http://uniicode.org/reports/tr15/#Hangul
 +			 */
 +			if (0 <= (LIndex = uc - HC_LBASE) &&
 +			    LIndex < HC_LCOUNT) {
 +				/*
 +				 * Hangul Composition.
 +				 * 1. Two current code points are L and V.
 +				 */
 +				int VIndex = uc2 - HC_VBASE;
 +				if (0 <= VIndex && VIndex < HC_VCOUNT) {
 +					/* Make syllable of form LV. */
 +					UPDATE_UC(HC_SBASE +
 +					    (LIndex * HC_VCOUNT + VIndex) *
 +					     HC_TCOUNT);
 +				} else {
 +					WRITE_UC();
 +					REPLACE_UC_WITH_UC2();
 +				}
 +				continue;
 +			} else if (0 <= (SIndex = uc - HC_SBASE) &&
 +			    SIndex < HC_SCOUNT && (SIndex % HC_TCOUNT) == 0) {
 +				/*
 +				 * Hangul Composition.
 +				 * 2. Two current code points are LV and T.
 +				 */
 +				int TIndex = uc2 - HC_TBASE;
 +				if (0 < TIndex && TIndex < HC_TCOUNT) {
 +					/* Make syllable of form LVT. */
 +					UPDATE_UC(uc + TIndex);
 +				} else {
 +					WRITE_UC();
 +					REPLACE_UC_WITH_UC2();
 +				}
 +				continue;
 +			} else if ((nfc = get_nfc(uc, uc2)) != 0) {
 +				/* A composition to current code points
 +				 * is found. */
 +				UPDATE_UC(nfc);
 +				continue;
 +			} else if ((cl = CCC(uc2)) == 0) {
 +				/* Clearly 'uc2' the second code point is not
 +				 * a decomposable code. */
 +				WRITE_UC();
 +				REPLACE_UC_WITH_UC2();
 +				continue;
 +			}
 +
 +			/*
 +			 * Collect following decomposable code points.
 +			 */
 +			cx = 0;
 +			ucx[0] = uc2;
 +			ccx[0] = cl;
 +			COLLECT_CPS(1);
 +
 +			/*
 +			 * Find a composed code in the collected code points.
 +			 */
 +			i = 1;
 +			while (i < ucx_size) {
 +				int j;
 +
 +				if ((nfc = get_nfc(uc, ucx[i])) == 0) {
 +					i++;
 +					continue;
 +				}
 +
 +				/*
 +				 * nfc is composed of uc and ucx[i].
 +				 */
 +				UPDATE_UC(nfc);
 +
 +				/*
 +				 * Remove ucx[i] by shifting
 +				 * follwoing code points.
 +				 */ 
 +				for (j = i; j+1 < ucx_size; j++) {
 +					ucx[j] = ucx[j+1];
 +					ccx[j] = ccx[j+1];
 +				}
 +				ucx_size --;
 +
 +				/*
 +				 * Collect following code points blocked
 +				 * by ucx[i] the removed code point.
 +				 */
 +				if (ucx_size > 0 && i == ucx_size &&
 +				    nx > 0 && cx == cl) {
 +					cl =  ccx[ucx_size-1];
 +					COLLECT_CPS(ucx_size);
 +				}
 +				/*
 +				 * Restart finding a composed code with
 +				 * the updated uc from the top of the
 +				 * collected code points.
 +				 */
 +				i = 0;
 +			}
 +
 +			/*
 +			 * Apparently the current code points are not
 +			 * decomposed characters or already composed.
 +			 */
 +			WRITE_UC();
 +			for (i = 0; i < ucx_size; i++)
 +				UNPARSE(p, endp, ucx[i]);
 +
 +			/*
 +			 * Flush out remaining canonical combining characters.
 +			 */
 +			if (nx > 0 && cx == cl && len > 0) {
 +				while ((nx = parse(&ucx[0], s, len))
 +				    > 0) {
 +					cx = CCC(ucx[0]);
 +					if (cl > cx)
 +						break;
 +					s += nx;
 +					len -= nx;
 +					cl = cx;
 +					UNPARSE(p, endp, ucx[0]);
 +				}
 +			}
 +			break;
 +		}
 +		if (n2 < 0) {
 +			WRITE_UC();
 +			/* Use a replaced unicode character. */
 +			UNPARSE(p, endp, uc2);
 +			s += n2*-1;
 +			len -= n2*-1;
 +			ret = -1;
 +			continue;
 +		} else if (n2 == 0) {
 +			WRITE_UC();
 +			break;
 +		}
 +	}
 +	as->length = p - as->s;
 +	as->s[as->length] = '\0';
 +	if (ts == 2)
 +		as->s[as->length+1] = '\0';
 +	return (ret);
 +}
 +
 +#if defined(__APPLE__)
 +
 +/*
 + * Normalize UTF-8 characters to Form D and copy the result.
 + */
 +static int
 +archive_string_normalize_D(struct archive_string *as, const void *_p,
 +    size_t len, struct archive_string_conv *sc)
 +{
 +	const UniChar *inp;
 +	char *outp;
 +	size_t newsize;
 +	ByteCount inCount, outCount;
 +	ByteCount inAvail, outAvail;
 +	OSStatus err;
 +	int ret, saved_flag;
 +
 +	/*
 +	 * Convert the current string to UTF-16LE for normalization.
 +	 * The character-set of the current string must be UTF-16BE or
 +	 * UTF-8.
 +	 */
 +	archive_string_empty(&(sc->utf16nfc));
 +	saved_flag = sc->flag;/* save a flag. */
 +	sc->flag &= ~(SCONV_TO_UTF16BE | SCONV_TO_UTF8);
 +	sc->flag |= SCONV_TO_UTF16LE;
 +	ret = archive_string_append_unicode(&(sc->utf16nfc), _p, len, sc);
 +	sc->flag = saved_flag;/* restore the saved flag */
 +	if (archive_strlen(&(sc->utf16nfc)) == 0) {
 +		if (archive_string_ensure(as, as->length + 1) == NULL)
 +			return (-1);
 +		return (ret);
 +	}
 +
 +	/*
 +	 * Normalize an NFC string to be an NFD(HFS Plus version).
 +	 */
 +	newsize = sc->utf16nfc.length + 2;
 +	if (archive_string_ensure(&(sc->utf16nfd), newsize) == NULL)
 +		return (-1);
 +
 +	inp = (UniChar *)sc->utf16nfc.s;
 +	inAvail = archive_strlen(&(sc->utf16nfc));
 +	sc->utf16nfd.length = 0;
 +	outp = sc->utf16nfd.s;
 +	outAvail = sc->utf16nfd.buffer_length -2;
 +
 +	do {
 +		/* Reinitialize all state information. */
 +		if (ResetUnicodeToTextInfo(sc->uniInfo) != noErr)
 +			goto return_no_changed_data;
 +
 +		inCount = outCount = 0;
 +		err = ConvertFromUnicodeToText(sc->uniInfo,
 +		    inAvail, inp,
 +		    kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL,
 +		    outAvail, &inCount, &outCount, outp);
 +
 +		if (err == noErr) {
 +			sc->utf16nfd.length = outCount;
 +			sc->utf16nfd.s[sc->utf16nfd.length] = 0;
 +			sc->utf16nfd.s[sc->utf16nfd.length+1] = 0;
 +		} else if (err == kTECOutputBufferFullStatus) {
 +			newsize = inAvail - inCount;
 +			if (newsize > inAvail)
 +				newsize = inAvail;
 +			newsize += sc->utf16nfd.buffer_length + 2;
 +			if (archive_string_ensure(&(sc->utf16nfd), newsize)
 +			    == NULL)
 +				return (-1);
 +			outp = sc->utf16nfd.s;
 +			outAvail = sc->utf16nfd.buffer_length -2;
 +		} else
 +			goto return_no_changed_data;
 +	} while (err == kTECOutputBufferFullStatus);
 +
 +	/*
 +	 * If there is a next-step conversion, we should convert
 +	 * a UTF-16LE(NFD) string back to the original Unicode type.
 +	 */
 +	saved_flag = sc->flag;/* save a flag. */
 +	if (!(sc->flag &
 +	    (SCONV_TO_UTF16BE | SCONV_TO_UTF16LE | SCONV_TO_UTF8))) {
 +		/*
 +		 * This case is going to be converted to another
 +		 * character-set through iconv.
 +		 */
 +		if (sc->flag & SCONV_FROM_UTF16BE)
 +			sc->flag |= SCONV_TO_UTF16BE;
 +		else if (sc->flag & SCONV_FROM_UTF16LE)
 +			sc->flag |= SCONV_TO_UTF16LE;
 +		else
 +			sc->flag |= SCONV_TO_UTF8;
 +	}
 +	sc->flag &= ~(SCONV_FROM_UTF16BE | SCONV_FROM_UTF8);
 +	sc->flag |= SCONV_FROM_UTF16LE;
 +	if (archive_string_append_unicode(as, sc->utf16nfd.s,
 +	    sc->utf16nfd.length, sc) != 0)
 +		ret = -1;
 +	sc->flag = saved_flag;/* restore the saved flag */
 +	return (ret);
 +
 +return_no_changed_data:
 +	/*
 +	 * Something conversion error happend, so we return a no normalized
 +	 * string with an error.
 +	 */
 +	(void)archive_string_append_unicode(as, _p, len, sc);
 +	return (-1);
 +}
 +
 +#endif /* __APPLE__ */
 +
 +/*
 + * libarchive 2.x made incorrect UTF-8 strings in the wrong assumuption
 + * that WCS is Unicode. it is true for servel platforms but some are false.
 + * And then people who did not use UTF-8 locale on the non Unicode WCS
 + * platform and made a tar file with libarchive(mostly bsdtar) 2.x. Those
 + * now cannot get right filename from libarchive 3.x and later since we
 + * fixed the wrong assumption and it is incompatible to older its versions.
 + * So we provide special option, "compat-2x.x", for resolving it.
 + * That option enable the string conversion of libarchive 2.x.
 + *
 + * Translates the wrong UTF-8 string made by libarchive 2.x into current
 + * locale character set and appends to the archive_string.
 + * Note: returns -1 if conversion fails.
 + */
 +static int
 +strncat_from_utf8_libarchive2(struct archive_string *as,
 +    const void *_p, size_t len, struct archive_string_conv *sc)
 +{
 +	const char *s;
 +	int n;
 +	char *p;
 +	char *end;
 +	uint32_t unicode;
 +#if HAVE_WCRTOMB
 +	mbstate_t shift_state;
 +
 +	memset(&shift_state, 0, sizeof(shift_state));
 +#else
 +	/* Clear the shift state before starting. */
 +	wctomb(NULL, L'\0');
 +#endif
 +	(void)sc; /* UNUSED */
 +	/*
 +	 * Allocate buffer for MBS.
 +	 * We need this allocation here since it is possible that
 +	 * as->s is still NULL.
 +	 */
 +	if (archive_string_ensure(as, as->length + len + 1) == NULL)
 +		return (-1);
 +
 +	s = (const char *)_p;
 +	p = as->s + as->length;
 +	end = as->s + as->buffer_length - MB_CUR_MAX -1;
 +	while ((n = _utf8_to_unicode(&unicode, s, len)) != 0) {
 +		wchar_t wc;
 +
 +		if (p >= end) {
 +			as->length = p - as->s;
 +			/* Re-allocate buffer for MBS. */
 +			if (archive_string_ensure(as,
 +			    as->length + len * 2 + 1) == NULL)
 +				return (-1);
 +			p = as->s + as->length;
 +			end = as->s + as->buffer_length - MB_CUR_MAX -1;
 +		}
 +
 +		/*
 +		 * As libarchie 2.x, translates the UTF-8 characters into
 +		 * wide-characters in the assumption that WCS is Unicode.
 +		 */
 +		if (n < 0) {
 +			n *= -1;
 +			wc = L'?';
 +		} else
 +			wc = (wchar_t)unicode;
 +
 +		s += n;
 +		len -= n;
 +		/*
 +		 * Translates the wide-character into the current locale MBS.
 +		 */
 +#if HAVE_WCRTOMB
 +		n = wcrtomb(p, wc, &shift_state);
 +#else
 +		n = wctomb(p, wc);
 +#endif
 +		if (n == -1)
 +			return (-1);
 +		p += n;
 +	}
 +	as->length = p - as->s;
 +	as->s[as->length] = '\0';
 +	return (0);
 +}
 +
 +
 +/*
 + * Conversion functions between current locale dependent MBS and UTF-16BE.
 + *   strncat_from_utf16be() : UTF-16BE --> MBS
 + *   strncat_to_utf16be()   : MBS --> UTF16BE
 + */
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +
 +/*
 + * Convert a UTF-16BE/LE string to current locale and copy the result.
 + * Return -1 if conversion failes.
 + */
 +static int
 +win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
 +    struct archive_string_conv *sc, int be)
 +{
 +	struct archive_string tmp;
 +	const char *u16;
 +	int ll;
 +	BOOL defchar;
 +	char *mbs;
 +	size_t mbs_size, b;
 +	int ret = 0;
 +
 +	bytes &= ~1;
 +	if (archive_string_ensure(as, as->length + bytes +1) == NULL)
 +		return (-1);
 +
 +	mbs = as->s + as->length;
 +	mbs_size = as->buffer_length - as->length -1;
 +
 +	if (sc->to_cp == CP_C_LOCALE) {
 +		/*
 +		 * "C" locale special process.
 +		 */
 +		u16 = _p;
 +		ll = 0;
 +		for (b = 0; b < bytes; b += 2) {
 +			uint16_t val;
 +			if (be)
 +				val = archive_be16dec(u16+b);
 +			else
 +				val = archive_le16dec(u16+b);
 +			if (val > 255) {
 +				*mbs++ = '?';
 +				ret = -1;
 +			} else
 +				*mbs++ = (char)(val&0xff);
 +			ll++;
 +		}
 +		as->length += ll;
 +		as->s[as->length] = '\0';
 +		return (ret);
 +	}
 +
 +	archive_string_init(&tmp);
 +	if (be) {
 +		if (is_big_endian()) {
 +			u16 = _p;
 +		} else {
 +			if (archive_string_ensure(&tmp, bytes+2) == NULL)
 +				return (-1);
 +			memcpy(tmp.s, _p, bytes);
 +			for (b = 0; b < bytes; b += 2) {
 +				uint16_t val = archive_be16dec(tmp.s+b);
 +				archive_le16enc(tmp.s+b, val);
 +			}
 +			u16 = tmp.s;
 +		}
 +	} else {
 +		if (!is_big_endian()) {
 +			u16 = _p;
 +		} else {
 +			if (archive_string_ensure(&tmp, bytes+2) == NULL)
 +				return (-1);
 +			memcpy(tmp.s, _p, bytes);
 +			for (b = 0; b < bytes; b += 2) {
 +				uint16_t val = archive_le16dec(tmp.s+b);
 +				archive_be16enc(tmp.s+b, val);
 +			}
 +			u16 = tmp.s;
 +		}
 +	}
 +
 +	do {
 +		defchar = 0;
 +		ll = WideCharToMultiByte(sc->to_cp, 0,
 +		    (LPCWSTR)u16, bytes>>1, mbs, mbs_size,
 +			NULL, &defchar);
 +		if (ll == 0 &&
 +		    GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
 +			/* Need more buffer for MBS. */
 +			ll = WideCharToMultiByte(sc->to_cp, 0,
 +			    (LPCWSTR)u16, bytes, NULL, 0, NULL, NULL);
 +			if (archive_string_ensure(as, ll +1) == NULL)
 +				return (-1);
 +			mbs = as->s + as->length;
 +			mbs_size = as->buffer_length - as->length -1;
 +			continue;
 +		}
 +	} while (0);
 +	archive_string_free(&tmp);
 +	as->length += ll;
 +	as->s[as->length] = '\0';
 +	if (ll == 0 || defchar)
 +		ret = -1;
 +	return (ret);
 +}
 +
 +static int
 +win_strncat_from_utf16be(struct archive_string *as, const void *_p, size_t bytes,
 +    struct archive_string_conv *sc)
 +{
 +	return (win_strncat_from_utf16(as, _p, bytes, sc, 1));
 +}
 +
 +static int
 +win_strncat_from_utf16le(struct archive_string *as, const void *_p, size_t bytes,
 +    struct archive_string_conv *sc)
 +{
 +	return (win_strncat_from_utf16(as, _p, bytes, sc, 0));
 +}
 +
 +static int
 +is_big_endian(void)
 +{
 +	uint16_t d = 1;
 +
 +	return (archive_be16dec(&d) == 1);
 +}
 +
 +/*
 + * Convert a current locale string to UTF-16BE/LE and copy the result.
 + * Return -1 if conversion failes.
 + */
 +static int
 +win_strncat_to_utf16(struct archive_string *as16, const void *_p, size_t length,
 +    struct archive_string_conv *sc, int bigendian)
 +{
 +	const char *s = (const char *)_p;
 +	char *u16;
 +	size_t count, avail;
 +
 +	if (archive_string_ensure(as16,
 +	    as16->length + (length + 1) * 2) == NULL)
 +		return (-1);
 +
 +	u16 = as16->s + as16->length;
 +	avail = as16->buffer_length - 2;
 +	if (sc->from_cp == CP_C_LOCALE) {
 +		/*
 +		 * "C" locale special process.
 +		 */
 +		count = 0;
 +		while (count < length && *s) {
 +			if (bigendian)
 +				archive_be16enc(u16, *s);
 +			else
 +				archive_le16enc(u16, *s);
 +			u16 += 2;
 +			s++;
 +			count++;
 +		}
 +		as16->length += count << 1;
 +		as16->s[as16->length] = 0;
 +		as16->s[as16->length+1] = 0;
 +		return (0);
 +	}
 +	do {
 +		count = MultiByteToWideChar(sc->from_cp,
 +		    MB_PRECOMPOSED, s, length, (LPWSTR)u16, (int)avail>>1);
 +		if (count == 0 &&
 +		    GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
 +			/* Need more buffer for UTF-16 string */
 +			count = MultiByteToWideChar(sc->from_cp,
 +			    MB_PRECOMPOSED, s, length, NULL, 0);
 +			if (archive_string_ensure(as16, (count +1) * 2)
 +			    == NULL)
 +				return (-1);
 +			u16 = as16->s + as16->length;
 +			avail = as16->buffer_length - 2;
 +			continue;
 +		}
 +	} while (0);
 +	as16->length += count * 2;
 +	as16->s[as16->length] = 0;
 +	as16->s[as16->length+1] = 0;
 +	if (count == 0)
 +		return (-1);
 +
 +	if (is_big_endian()) {
 +		if (!bigendian) {
 +			while (count > 0) {
 +				uint16_t v = archive_be16dec(u16);
 +				archive_le16enc(u16, v);
 +				u16 += 2;
 +				count--;
 +			}
 +		}
 +	} else {
 +		if (bigendian) {
 +			while (count > 0) {
 +				uint16_t v = archive_le16dec(u16);
 +				archive_be16enc(u16, v);
 +				u16 += 2;
 +				count--;
 +			}
 +		}
 +	}
 +	return (0);
 +}
 +
 +static int
 +win_strncat_to_utf16be(struct archive_string *as16, const void *_p, size_t length,
 +    struct archive_string_conv *sc)
 +{
 +	return (win_strncat_to_utf16(as16, _p, length, sc, 1));
 +}
 +
 +static int
 +win_strncat_to_utf16le(struct archive_string *as16, const void *_p, size_t length,
 +    struct archive_string_conv *sc)
 +{
 +	return (win_strncat_to_utf16(as16, _p, length, sc, 0));
 +}
 +
 +#endif /* _WIN32 && !__CYGWIN__ */
 +
 +/*
 + * Do the best effort for conversions.
 + * We cannot handle UTF-16BE character-set without such iconv,
 + * but there is a chance if a string consists just ASCII code or
 + * a current locale is UTF-8.
 + */
 +
 +/*
 + * Convert a UTF-16BE string to current locale and copy the result.
 + * Return -1 if conversion failes.
 + */
 +static int
 +best_effort_strncat_from_utf16(struct archive_string *as, const void *_p,
 +    size_t bytes, struct archive_string_conv *sc, int be)
 +{
 +	const char *utf16 = (const char *)_p;
 +	char *mbs;
 +	uint32_t uc;
 +	int n, ret;
 +
 +	(void)sc; /* UNUSED */
 +	/*
 +	 * Other case, we should do the best effort.
 +	 * If all character are ASCII(<0x7f), we can convert it.
 +	 * if not , we set a alternative character and return -1.
 +	 */
 +	ret = 0;
 +	if (archive_string_ensure(as, as->length + bytes +1) == NULL)
 +		return (-1);
 +	mbs = as->s + as->length;
 +
 +	while ((n = utf16_to_unicode(&uc, utf16, bytes, be)) != 0) {
 +		if (n < 0) {
 +			n *= -1;
 +			ret =  -1;
 +		}
 +		bytes -= n;
 +		utf16 += n;
 +
 +		if (uc > 127) {
 +			/* We cannot handle it. */
 +			*mbs++ = '?';
 +			ret =  -1;
 +		} else
 +			*mbs++ = (char)uc;
 +	}
 +	as->length = mbs - as->s;
 +	as->s[as->length] = '\0';
 +	return (ret);
 +}
 +
 +static int
 +best_effort_strncat_from_utf16be(struct archive_string *as, const void *_p,
 +    size_t bytes, struct archive_string_conv *sc)
 +{
 +	return (best_effort_strncat_from_utf16(as, _p, bytes, sc, 1));
 +}
 +
 +static int
 +best_effort_strncat_from_utf16le(struct archive_string *as, const void *_p,
 +    size_t bytes, struct archive_string_conv *sc)
 +{
 +	return (best_effort_strncat_from_utf16(as, _p, bytes, sc, 0));
 +}
 +
 +/*
 + * Convert a current locale string to UTF-16BE/LE and copy the result.
 + * Return -1 if conversion failes.
 + */
 +static int
 +best_effort_strncat_to_utf16(struct archive_string *as16, const void *_p,
 +    size_t length, struct archive_string_conv *sc, int bigendian)
 +{
 +	const char *s = (const char *)_p;
 +	char *utf16;
 +	size_t remaining;
 +	int ret;
 +
 +	(void)sc; /* UNUSED */
 +	/*
 +	 * Other case, we should do the best effort.
 +	 * If all character are ASCII(<0x7f), we can convert it.
 +	 * if not , we set a alternative character and return -1.
 +	 */
 +	ret = 0;
 +	remaining = length;
 +
 +	if (archive_string_ensure(as16,
 +	    as16->length + (length + 1) * 2) == NULL)
 +		return (-1);
 +
 +	utf16 = as16->s + as16->length;
 +	while (remaining--) {
 +		unsigned c = *s++;
 +		if (c > 127) {
 +			/* We cannot handle it. */
 +			c = UNICODE_R_CHAR;
 +			ret = -1;
 +		}
 +		if (bigendian)
 +			archive_be16enc(utf16, c);
 +		else
 +			archive_le16enc(utf16, c);
 +		utf16 += 2;
 +	}
 +	as16->length = utf16 - as16->s;
 +	as16->s[as16->length] = 0;
 +	as16->s[as16->length+1] = 0;
 +	return (ret);
 +}
 +
 +static int
 +best_effort_strncat_to_utf16be(struct archive_string *as16, const void *_p,
 +    size_t length, struct archive_string_conv *sc)
 +{
 +	return (best_effort_strncat_to_utf16(as16, _p, length, sc, 1));
 +}
 +
 +static int
 +best_effort_strncat_to_utf16le(struct archive_string *as16, const void *_p,
 +    size_t length, struct archive_string_conv *sc)
 +{
 +	return (best_effort_strncat_to_utf16(as16, _p, length, sc, 0));
 +}
 +
 +
 +/*
 + * Multistring operations.
 + */
 +
 +void
 +archive_mstring_clean(struct archive_mstring *aes)
 +{
 +	archive_wstring_free(&(aes->aes_wcs));
 +	archive_string_free(&(aes->aes_mbs));
 +	archive_string_free(&(aes->aes_utf8));
 +	archive_string_free(&(aes->aes_mbs_in_locale));
 +	aes->aes_set = 0;
 +}
 +
 +void
 +archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring *src)
 +{
 +	dest->aes_set = src->aes_set;
 +	archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs));
 +	archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8));
 +	archive_wstring_copy(&(dest->aes_wcs), &(src->aes_wcs));
 +}
 +
 +int
 +archive_mstring_get_utf8(struct archive *a, struct archive_mstring *aes,
 +  const char **p)
 +{
 +	struct archive_string_conv *sc;
 +	int r;
 +
 +	/* If we already have a UTF8 form, return that immediately. */
 +	if (aes->aes_set & AES_SET_UTF8) {
 +		*p = aes->aes_utf8.s;
 +		return (0);
 +	}
 +
 +	*p = NULL;
 +	if (aes->aes_set & AES_SET_MBS) {
 +		sc = archive_string_conversion_to_charset(a, "UTF-8", 1);
 +		if (sc == NULL)
 +			return (-1);/* Couldn't allocate memory for sc. */
 +		r = archive_strncpy_in_locale(&(aes->aes_mbs), aes->aes_mbs.s,
 +		    aes->aes_mbs.length, sc);
 +		if (a == NULL)
 +			free_sconv_object(sc);
 +		if (r == 0) {
 +			aes->aes_set |= AES_SET_UTF8;
 +			*p = aes->aes_utf8.s;
 +			return (0);/* success. */
 +		} else
 +			return (-1);/* failure. */
 +	}
 +	return (0);/* success. */
 +}
 +
 +int
 +archive_mstring_get_mbs(struct archive *a, struct archive_mstring *aes,
 +    const char **p)
 +{
 +	int r, ret = 0;
 +
 +	(void)a; /* UNUSED */
 +	/* If we already have an MBS form, return that immediately. */
 +	if (aes->aes_set & AES_SET_MBS) {
 +		*p = aes->aes_mbs.s;
 +		return (ret);
 +	}
 +
 +	*p = NULL;
 +	/* If there's a WCS form, try converting with the native locale. */
 +	if (aes->aes_set & AES_SET_WCS) {
 +		archive_string_empty(&(aes->aes_mbs));
 +		r = archive_string_append_from_wcs(&(aes->aes_mbs),
 +		    aes->aes_wcs.s, aes->aes_wcs.length);
 +		*p = aes->aes_mbs.s;
 +		if (r == 0) {
 +			aes->aes_set |= AES_SET_MBS;
 +			return (ret);
 +		} else
 +			ret = -1;
 +	}
 +
 +	/*
 +	 * Only a UTF-8 form cannot avail because its conversion already
 +	 * failed at archive_mstring_update_utf8().
 +	 */
 +	return (ret);
 +}
 +
 +int
 +archive_mstring_get_wcs(struct archive *a, struct archive_mstring *aes,
 +    const wchar_t **wp)
 +{
 +	int r, ret = 0;
 +
 +	(void)a;/* UNUSED */
 +	/* Return WCS form if we already have it. */
 +	if (aes->aes_set & AES_SET_WCS) {
 +		*wp = aes->aes_wcs.s;
 +		return (ret);
 +	}
 +
 +	*wp = NULL;
 +	/* Try converting MBS to WCS using native locale. */
 +	if (aes->aes_set & AES_SET_MBS) {
 +		archive_wstring_empty(&(aes->aes_wcs));
 +		r = archive_wstring_append_from_mbs(&(aes->aes_wcs),
 +		    aes->aes_mbs.s, aes->aes_mbs.length);
 +		if (r == 0) {
 +			aes->aes_set |= AES_SET_WCS;
 +			*wp = aes->aes_wcs.s;
 +		} else
 +			ret = -1;/* failure. */
 +	}
 +	return (ret);
 +}
 +
 +int
 +archive_mstring_get_mbs_l(struct archive_mstring *aes,
 +    const char **p, size_t *length, struct archive_string_conv *sc)
 +{
 +	int r, ret = 0;
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +	/*
 +	 * Internationalization programing on Windows must use Wide
 +	 * characters because Windows platform cannot make locale UTF-8.
 +	 */
 +	if (sc != NULL && (aes->aes_set & AES_SET_WCS) != 0) {
 +		archive_string_empty(&(aes->aes_mbs_in_locale));
 +		r = archive_string_append_from_wcs_in_codepage(
 +		    &(aes->aes_mbs_in_locale), aes->aes_wcs.s,
 +		    aes->aes_wcs.length, sc);
 +		if (r == 0) {
 +			*p = aes->aes_mbs_in_locale.s;
 +			if (length != NULL)
 +				*length = aes->aes_mbs_in_locale.length;
 +			return (0);
 +		} else if (errno == ENOMEM)
 +			return (-1);
 +		else
 +			ret = -1;
 +	}
 +#endif
 +
 +	/* If there is not an MBS form but is a WCS form, try converting
 +	 * with the native locale to be used for translating it to specified
 +	 * character-set. */
 +	if ((aes->aes_set & AES_SET_MBS) == 0 &&
 +	    (aes->aes_set & AES_SET_WCS) != 0) {
 +		archive_string_empty(&(aes->aes_mbs));
 +		r = archive_string_append_from_wcs(&(aes->aes_mbs),
 +		    aes->aes_wcs.s, aes->aes_wcs.length);
 +		if (r == 0)
 +			aes->aes_set |= AES_SET_MBS;
 +		else if (errno == ENOMEM)
 +			return (-1);
 +		else
 +			ret = -1;
 +	}
 +	/* If we already have an MBS form, use it to be translated to
 +	 * specified character-set. */
 +	if (aes->aes_set & AES_SET_MBS) {
 +		if (sc == NULL) {
 +			/* Conversion is unneeded. */
 +			*p = aes->aes_mbs.s;
 +			if (length != NULL)
 +				*length = aes->aes_mbs.length;
 +			return (0);
 +		}
 +		ret = archive_strncpy_in_locale(&(aes->aes_mbs_in_locale),
 +		    aes->aes_mbs.s, aes->aes_mbs.length, sc);
 +		*p = aes->aes_mbs_in_locale.s;
 +		if (length != NULL)
 +			*length = aes->aes_mbs_in_locale.length;
 +	} else {
 +		*p = NULL;
 +		if (length != NULL)
 +			*length = 0;
 +	}
 +	return (ret);
 +}
 +
 +int
 +archive_mstring_copy_mbs(struct archive_mstring *aes, const char *mbs)
 +{
 +	if (mbs == NULL) {
 +		aes->aes_set = 0;
 +		return (0);
 +	}
 +	return (archive_mstring_copy_mbs_len(aes, mbs, strlen(mbs)));
 +}
 +
 +int
 +archive_mstring_copy_mbs_len(struct archive_mstring *aes, const char *mbs,
 +    size_t len)
 +{
 +	if (mbs == NULL) {
 +		aes->aes_set = 0;
 +		return (0);
 +	}
 +	aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */
 +	archive_strncpy(&(aes->aes_mbs), mbs, len);
 +	archive_string_empty(&(aes->aes_utf8));
 +	archive_wstring_empty(&(aes->aes_wcs));
 +	return (0);
 +}
 +
 +int
 +archive_mstring_copy_wcs(struct archive_mstring *aes, const wchar_t *wcs)
 +{
 +	return archive_mstring_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs));
 +}
 +
 +int
 +archive_mstring_copy_wcs_len(struct archive_mstring *aes, const wchar_t *wcs,
 +    size_t len)
 +{
 +	if (wcs == NULL) {
 +		aes->aes_set = 0;
 +	}
 +	aes->aes_set = AES_SET_WCS; /* Only WCS form set. */
 +	archive_string_empty(&(aes->aes_mbs));
 +	archive_string_empty(&(aes->aes_utf8));
 +	archive_wstrncpy(&(aes->aes_wcs), wcs, len);
 +	return (0);
 +}
 +
 +int
 +archive_mstring_copy_mbs_len_l(struct archive_mstring *aes,
 +    const char *mbs, size_t len, struct archive_string_conv *sc)
 +{
 +	int r;
 +
 +	if (mbs == NULL) {
 +		aes->aes_set = 0;
 +		return (0);
 +	}
 +	archive_string_empty(&(aes->aes_mbs));
 +	archive_wstring_empty(&(aes->aes_wcs));
 +	archive_string_empty(&(aes->aes_utf8));
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +	/*
 +	 * Internationalization programing on Windows must use Wide
 +	 * characters because Windows platform cannot make locale UTF-8.
 +	 */
 +	if (sc == NULL) {
- 		archive_string_append(&(aes->aes_mbs),
- 		    mbs, mbsnbytes(mbs, len));
- 		aes->aes_set = AES_SET_MBS;
- 		r = 0;
++		if (archive_string_append(&(aes->aes_mbs),
++			mbs, mbsnbytes(mbs, len)) == NULL) {
++			aes->aes_set = 0;
++			r = -1;
++		} else {
++			aes->aes_set = AES_SET_MBS;
++			r = 0;
++		}
 +#if defined(HAVE_ICONV)
 +	} else if (sc != NULL && sc->cd_w != (iconv_t)-1) {
 +		/*
 +		 * This case happens only when MultiByteToWideChar() cannot
 +		 * handle sc->from_cp, and we have to iconv in order to
 +		 * translate character-set to wchar_t,UTF-16.
 +		 */
 +		iconv_t cd = sc->cd;
 +		unsigned from_cp;
 +		int flag;
 +
 +		/*
 +		 * Translate multi-bytes from some character-set to UTF-8.
 +		 */ 
 +		sc->cd = sc->cd_w;
 +		r = archive_strncpy_in_locale(&(aes->aes_utf8), mbs, len, sc);
 +		sc->cd = cd;
 +		if (r != 0) {
 +			aes->aes_set = 0;
 +			return (r);
 +		}
 +		aes->aes_set = AES_SET_UTF8;
 +
 +		/*
 +		 * Append the UTF-8 string into wstring.
 +		 */ 
 +		flag = sc->flag;
 +		sc->flag &= ~(SCONV_NORMALIZATION_C
 +				| SCONV_TO_UTF16| SCONV_FROM_UTF16);
 +		from_cp = sc->from_cp;
 +		sc->from_cp = CP_UTF8;
 +		r = archive_wstring_append_from_mbs_in_codepage(&(aes->aes_wcs),
 +			aes->aes_utf8.s, aes->aes_utf8.length, sc);
 +		sc->flag = flag;
 +		sc->from_cp = from_cp;
 +		if (r == 0)
 +			aes->aes_set |= AES_SET_WCS;
 +#endif
 +	} else {
 +		r = archive_wstring_append_from_mbs_in_codepage(
 +		    &(aes->aes_wcs), mbs, len, sc);
 +		if (r == 0)
 +			aes->aes_set = AES_SET_WCS;
 +		else
 +			aes->aes_set = 0;
 +	}
 +#else
 +	r = archive_strncpy_in_locale(&(aes->aes_mbs), mbs, len, sc);
 +	if (r == 0)
 +		aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */
 +	else
 +		aes->aes_set = 0;
 +#endif
 +	return (r);
 +}
 +
 +/*
 + * The 'update' form tries to proactively update all forms of
 + * this string (WCS and MBS) and returns an error if any of
 + * them fail.  This is used by the 'pax' handler, for instance,
 + * to detect and report character-conversion failures early while
 + * still allowing clients to get potentially useful values from
 + * the more tolerant lazy conversions.  (get_mbs and get_wcs will
 + * strive to give the user something useful, so you can get hopefully
 + * usable values even if some of the character conversions are failing.)
 + */
 +int
 +archive_mstring_update_utf8(struct archive *a, struct archive_mstring *aes,
 +    const char *utf8)
 +{
 +	struct archive_string_conv *sc;
 +	int r;
 +
 +	if (utf8 == NULL) {
 +		aes->aes_set = 0;
 +		return (0); /* Succeeded in clearing everything. */
 +	}
 +
 +	/* Save the UTF8 string. */
 +	archive_strcpy(&(aes->aes_utf8), utf8);
 +
 +	/* Empty the mbs and wcs strings. */
 +	archive_string_empty(&(aes->aes_mbs));
 +	archive_wstring_empty(&(aes->aes_wcs));
 +
 +	aes->aes_set = AES_SET_UTF8;	/* Only UTF8 is set now. */
 +
 +	/* Try converting UTF-8 to MBS, return false on failure. */
 +	sc = archive_string_conversion_from_charset(a, "UTF-8", 1);
 +	if (sc == NULL)
 +		return (-1);/* Couldn't allocate memory for sc. */
 +	r = archive_strcpy_in_locale(&(aes->aes_mbs), utf8, sc);
 +	if (a == NULL)
 +		free_sconv_object(sc);
 +	if (r != 0)
 +		return (-1);
 +	aes->aes_set = AES_SET_UTF8 | AES_SET_MBS; /* Both UTF8 and MBS set. */
 +
 +	/* Try converting MBS to WCS, return false on failure. */
 +	if (archive_wstring_append_from_mbs(&(aes->aes_wcs), aes->aes_mbs.s,
 +	    aes->aes_mbs.length))
 +		return (-1);
 +	aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS;
 +
 +	/* All conversions succeeded. */
 +	return (0);
 +}
diff --cc Utilities/cmlibarchive/libarchive/archive_windows.c
index 51860ac,0000000..8f5d566
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_windows.c
+++ b/Utilities/cmlibarchive/libarchive/archive_windows.c
@@@ -1,845 -1,0 +1,813 @@@
 +/*-
 + * Copyright (c) 2009-2011 Michihiro NAKAJIMA
 + * Copyright (c) 2003-2007 Kees Zeelenberg
 + * 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$
 + */
 +
 +/*
 + * A set of compatibility glue for building libarchive on Windows platforms.
 + *
 + * Originally created as "libarchive-nonposix.c" by Kees Zeelenberg
 + * for the GnuWin32 project, trimmed significantly by Tim Kientzle.
 + *
 + * Much of the original file was unnecessary for libarchive, because
 + * many of the features it emulated were not strictly necessary for
 + * libarchive.  I hope for this to shrink further as libarchive
 + * internals are gradually reworked to sit more naturally on both
 + * POSIX and Windows.  Any ideas for this are greatly appreciated.
 + *
 + * The biggest remaining issue is the dev/ino emulation; libarchive
 + * has a couple of public APIs that rely on dev/ino uniquely
 + * identifying a file.  This doesn't match well with Windows.  I'm
 + * considering alternative APIs.
 + */
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +
 +#include "archive_platform.h"
 +#include "archive_private.h"
 +#include <ctype.h>
 +#include <errno.h>
 +#include <stddef.h>
 +#ifdef HAVE_SYS_UTIME_H
 +#include <sys/utime.h>
 +#endif
 +#include <sys/stat.h>
 +#include <locale.h>
 +#include <process.h>
 +#include <stdlib.h>
 +#include <wchar.h>
 +#include <windows.h>
 +#include <share.h>
 +
 +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 +
 +#if defined(__LA_LSEEK_NEEDED)
 +static BOOL SetFilePointerEx_perso(HANDLE hFile,
 +				   LARGE_INTEGER liDistanceToMove,
 +				   PLARGE_INTEGER lpNewFilePointer,
 +				   DWORD dwMoveMethod)
 +{
 +	LARGE_INTEGER li;
 +	li.QuadPart = liDistanceToMove.QuadPart;
 +	li.LowPart = SetFilePointer(
 +		hFile, li.LowPart, &li.HighPart, dwMoveMethod);
 +	if(lpNewFilePointer) {
 +		lpNewFilePointer->QuadPart = li.QuadPart;
 +	}
 +	return li.LowPart != -1 || GetLastError() == NO_ERROR;
 +}
 +#endif
 +
 +struct ustat {
 +	int64_t		st_atime;
 +	uint32_t	st_atime_nsec;
 +	int64_t		st_ctime;
 +	uint32_t	st_ctime_nsec;
 +	int64_t		st_mtime;
 +	uint32_t	st_mtime_nsec;
 +	gid_t		st_gid;
 +	/* 64bits ino */
 +	int64_t		st_ino;
 +	mode_t		st_mode;
 +	uint32_t	st_nlink;
 +	uint64_t	st_size;
 +	uid_t		st_uid;
 +	dev_t		st_dev;
 +	dev_t		st_rdev;
 +};
 +
 +/* Transform 64-bits ino into 32-bits by hashing.
 + * You do not forget that really unique number size is 64-bits.
 + */
 +#define INOSIZE (8*sizeof(ino_t)) /* 32 */
 +static __inline ino_t
 +getino(struct ustat *ub)
 +{
 +	ULARGE_INTEGER ino64;
 +	ino64.QuadPart = ub->st_ino;
 +	/* I don't know this hashing is correct way */
 +	return (ino64.LowPart ^ (ino64.LowPart >> INOSIZE));
 +}
 +
 +/*
 + * Prepend "\\?\" to the path name and convert it to unicode to permit
 + * an extended-length path for a maximum total path length of 32767
 + * characters.
 + * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx
 + */
 +wchar_t *
 +__la_win_permissive_name(const char *name)
 +{
 +	wchar_t *wn;
 +	wchar_t *ws;
 +	size_t ll;
 +
 +	ll = strlen(name);
 +	wn = malloc((ll + 1) * sizeof(wchar_t));
 +	if (wn == NULL)
 +		return (NULL);
 +	ll = mbstowcs(wn, name, ll);
 +	if (ll == (size_t)-1) {
 +		free(wn);
 +		return (NULL);
 +	}
 +	wn[ll] = L'\0';
 +	ws = __la_win_permissive_name_w(wn);
 +	free(wn);
 +	return (ws);
 +}
 +
 +wchar_t *
 +__la_win_permissive_name_w(const wchar_t *wname)
 +{
 +	wchar_t *wn, *wnp;
 +	wchar_t *ws, *wsp;
 +	DWORD l, len, slen;
 +	int unc;
 +
 +	/* Get a full-pathname. */
 +	l = GetFullPathNameW(wname, 0, NULL, NULL);
 +	if (l == 0)
 +		return (NULL);
++	/* NOTE: GetFullPathNameW has a bug that if the length of the file
++	 * name is just one that return imcomplete buffer size. Thus, we 
++	 * have to add three to the size to allocate a sufficient buffer
++	 * size for the full-pathname of the file name. */
++	l += 3;
 +	wnp = malloc(l * sizeof(wchar_t));
 +	if (wnp == NULL)
 +		return (NULL);
 +	len = GetFullPathNameW(wname, l, wnp, NULL);
 +	wn = wnp;
 +
 +	if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
 +	    wnp[2] == L'?' && wnp[3] == L'\\')
 +		/* We have already a permissive name. */
 +		return (wn);
 +
 +	if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
 +		wnp[2] == L'.' && wnp[3] == L'\\') {
 +		/* This is a device name */
 +		if (((wnp[4] >= L'a' && wnp[4] <= L'z') ||
 +		     (wnp[4] >= L'A' && wnp[4] <= L'Z')) &&
 +		    wnp[5] == L':' && wnp[6] == L'\\')
 +			wnp[2] = L'?';/* Not device name. */
 +		return (wn);
 +	}
 +
 +	unc = 0;
 +	if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {
 +		wchar_t *p = &wnp[2];
 +
 +		/* Skip server-name letters. */
 +		while (*p != L'\\' && *p != L'\0')
 +			++p;
 +		if (*p == L'\\') {
 +			wchar_t *rp = ++p;
 +			/* Skip share-name letters. */
 +			while (*p != L'\\' && *p != L'\0')
 +				++p;
 +			if (*p == L'\\' && p != rp) {
 +				/* Now, match patterns such as
 +				 * "\\server-name\share-name\" */
 +				wnp += 2;
 +				len -= 2;
 +				unc = 1;
 +			}
 +		}
 +	}
 +
 +	slen = 4 + (unc * 4) + len + 1;
 +	ws = wsp = malloc(slen * sizeof(wchar_t));
 +	if (ws == NULL) {
 +		free(wn);
 +		return (NULL);
 +	}
 +	/* prepend "\\?\" */
 +	wcsncpy(wsp, L"\\\\?\\", 4);
 +	wsp += 4;
 +	slen -= 4;
 +	if (unc) {
 +		/* append "UNC\" ---> "\\?\UNC\" */
 +		wcsncpy(wsp, L"UNC\\", 4);
 +		wsp += 4;
 +		slen -= 4;
 +	}
 +	wcsncpy(wsp, wnp, slen);
 +	wsp[slen - 1] = L'\0'; /* Ensure null termination. */
 +	free(wn);
 +	return (ws);
 +}
 +
 +/*
 + * Create a file handle.
 + * This can exceed MAX_PATH limitation.
 + */
 +static HANDLE
 +la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
 +    LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
 +    DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
 +{
 +	wchar_t *wpath;
 +	HANDLE handle;
 +
 +	handle = CreateFileA(path, dwDesiredAccess, dwShareMode,
 +	    lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
 +	    hTemplateFile);
 +	if (handle != INVALID_HANDLE_VALUE)
 +		return (handle);
 +	if (GetLastError() != ERROR_PATH_NOT_FOUND)
 +		return (handle);
 +	wpath = __la_win_permissive_name(path);
 +	if (wpath == NULL)
 +		return (handle);
 +	handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode,
 +	    lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
 +	    hTemplateFile);
 +	free(wpath);
 +	return (handle);
 +}
 +
- /*
-  * This fcntl is limited implementation.
-  */
- int
- __la_fcntl(int fd, int cmd, int val)
- {
- 	HANDLE handle;
- 
- 	handle = (HANDLE)_get_osfhandle(fd);
- 	if (GetFileType(handle) == FILE_TYPE_PIPE) {
- 		if (cmd == F_SETFL && val == 0) {
- 			DWORD mode = PIPE_WAIT;
- 			if (SetNamedPipeHandleState(
- 			    handle, &mode, NULL, NULL) != 0)
- 				return (0);
- 		}
- 	}
- 	errno = EINVAL;
- 	return (-1);
- }
- 
 +#if defined(__LA_LSEEK_NEEDED)
 +__int64
 +__la_lseek(int fd, __int64 offset, int whence)
 +{
 +	LARGE_INTEGER distance;
 +	LARGE_INTEGER newpointer;
 +	HANDLE handle;
 +
 +	if (fd < 0) {
 +		errno = EBADF;
 +		return (-1);
 +	}
 +	handle = (HANDLE)_get_osfhandle(fd);
 +	if (GetFileType(handle) != FILE_TYPE_DISK) {
 +		errno = EBADF;
 +		return (-1);
 +	}
 +	distance.QuadPart = offset;
 +	if (!SetFilePointerEx_perso(handle, distance, &newpointer, whence)) {
 +		DWORD lasterr;
 +
 +		lasterr = GetLastError();
 +		if (lasterr == ERROR_BROKEN_PIPE)
 +			return (0);
 +		if (lasterr == ERROR_ACCESS_DENIED)
 +			errno = EBADF;
 +		else
 +			la_dosmaperr(lasterr);
 +		return (-1);
 +	}
 +	return (newpointer.QuadPart);
 +}
 +#endif
 +
 +/* This can exceed MAX_PATH limitation. */
 +int
 +__la_open(const char *path, int flags, ...)
 +{
 +	va_list ap;
 +	wchar_t *ws;
 +	int r, pmode;
 +	DWORD attr;
 +
 +	va_start(ap, flags);
 +	pmode = va_arg(ap, int);
 +	va_end(ap);
 +	ws = NULL;
 +	if ((flags & ~O_BINARY) == O_RDONLY) {
 +		/*
 +		 * When we open a directory, _open function returns 
 +		 * "Permission denied" error.
 +		 */
 +		attr = GetFileAttributesA(path);
 +		if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) {
 +			ws = __la_win_permissive_name(path);
 +			if (ws == NULL) {
 +				errno = EINVAL;
 +				return (-1);
 +			}
 +			attr = GetFileAttributesW(ws);
 +		}
 +		if (attr == (DWORD)-1) {
 +			la_dosmaperr(GetLastError());
 +			free(ws);
 +			return (-1);
 +		}
 +		if (attr & FILE_ATTRIBUTE_DIRECTORY) {
 +			HANDLE handle;
 +
 +			if (ws != NULL)
 +				handle = CreateFileW(ws, 0, 0, NULL,
 +				    OPEN_EXISTING,
 +				    FILE_FLAG_BACKUP_SEMANTICS |
 +				    FILE_ATTRIBUTE_READONLY,
 +					NULL);
 +			else
 +				handle = CreateFileA(path, 0, 0, NULL,
 +				    OPEN_EXISTING,
 +				    FILE_FLAG_BACKUP_SEMANTICS |
 +				    FILE_ATTRIBUTE_READONLY,
 +					NULL);
 +			free(ws);
 +			if (handle == INVALID_HANDLE_VALUE) {
 +				la_dosmaperr(GetLastError());
 +				return (-1);
 +			}
 +			r = _open_osfhandle((intptr_t)handle, _O_RDONLY);
 +			return (r);
 +		}
 +	}
 +	if (ws == NULL) {
 +#if defined(__BORLANDC__)
 +		/* Borland has no mode argument.
 +		   TODO: Fix mode of new file.  */
 +		r = _open(path, flags);
 +#else
 +		r = _open(path, flags, pmode);
 +#endif
 +		if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
 +			/* Simulate other POSIX system action to pass our test suite. */
 +			attr = GetFileAttributesA(path);
 +			if (attr == (DWORD)-1)
 +				la_dosmaperr(GetLastError());
 +			else if (attr & FILE_ATTRIBUTE_DIRECTORY)
 +				errno = EISDIR;
 +			else
 +				errno = EACCES;
 +			return (-1);
 +		}
 +		if (r >= 0 || errno != ENOENT)
 +			return (r);
 +		ws = __la_win_permissive_name(path);
 +		if (ws == NULL) {
 +			errno = EINVAL;
 +			return (-1);
 +		}
 +	}
 +	r = _wopen(ws, flags, pmode);
 +	if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
 +		/* Simulate other POSIX system action to pass our test suite. */
 +		attr = GetFileAttributesW(ws);
 +		if (attr == (DWORD)-1)
 +			la_dosmaperr(GetLastError());
 +		else if (attr & FILE_ATTRIBUTE_DIRECTORY)
 +			errno = EISDIR;
 +		else
 +			errno = EACCES;
 +	}
 +	free(ws);
 +	return (r);
 +}
 +
 +ssize_t
 +__la_read(int fd, void *buf, size_t nbytes)
 +{
 +	HANDLE handle;
 +	DWORD bytes_read, lasterr;
 +	int r;
 +
 +#ifdef _WIN64
 +	if (nbytes > UINT32_MAX)
 +		nbytes = UINT32_MAX;
 +#endif
 +	if (fd < 0) {
 +		errno = EBADF;
 +		return (-1);
 +	}
 +	/* Do not pass 0 to third parameter of ReadFile(), read bytes.
 +	 * This will not return to application side. */
 +	if (nbytes == 0)
 +		return (0);
 +	handle = (HANDLE)_get_osfhandle(fd);
- 	if (GetFileType(handle) == FILE_TYPE_PIPE) {
- 		DWORD sta;
- 		if (GetNamedPipeHandleState(
- 		    handle, &sta, NULL, NULL, NULL, NULL, 0) != 0 &&
- 		    (sta & PIPE_NOWAIT) == 0) {
- 			DWORD avail = -1;
- 			int cnt = 3;
- 
- 			while (PeekNamedPipe(
- 			    handle, NULL, 0, NULL, &avail, NULL) != 0 &&
- 			    avail == 0 && --cnt)
- 				Sleep(100);
- 			if (avail == 0)
- 				return (0);
- 		}
- 	}
 +	r = ReadFile(handle, buf, (uint32_t)nbytes,
 +	    &bytes_read, NULL);
 +	if (r == 0) {
 +		lasterr = GetLastError();
 +		if (lasterr == ERROR_NO_DATA) {
 +			errno = EAGAIN;
 +			return (-1);
 +		}
 +		if (lasterr == ERROR_BROKEN_PIPE)
 +			return (0);
 +		if (lasterr == ERROR_ACCESS_DENIED)
 +			errno = EBADF;
 +		else
 +			la_dosmaperr(lasterr);
 +		return (-1);
 +	}
 +	return ((ssize_t)bytes_read);
 +}
 +
 +/* Convert Windows FILETIME to UTC */
 +__inline static void
 +fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns)
 +{
 +	ULARGE_INTEGER utc;
 +
 +	utc.HighPart = filetime->dwHighDateTime;
 +	utc.LowPart  = filetime->dwLowDateTime;
 +	if (utc.QuadPart >= EPOC_TIME) {
 +		utc.QuadPart -= EPOC_TIME;
 +		*time = (time_t)(utc.QuadPart / 10000000);	/* milli seconds base */
 +		*ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
 +	} else {
 +		*time = 0;
 +		*ns = 0;
 +	}
 +}
 +
 +/* Stat by handle
 + * Windows' stat() does not accept the path added "\\?\" especially "?"
 + * character.
 + * It means we cannot access the long name path longer than MAX_PATH.
 + * So I've implemented simular Windows' stat() to access the long name path.
 + * And I've added some feature.
 + * 1. set st_ino by nFileIndexHigh and nFileIndexLow of
 + *    BY_HANDLE_FILE_INFORMATION.
 + * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION.
 + * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION.
 + */
 +static int
 +__hstat(HANDLE handle, struct ustat *st)
 +{
 +	BY_HANDLE_FILE_INFORMATION info;
 +	ULARGE_INTEGER ino64;
 +	DWORD ftype;
 +	mode_t mode;
 +	time_t time;
 +	long ns;
 +
 +	switch (ftype = GetFileType(handle)) {
 +	case FILE_TYPE_UNKNOWN:
 +		errno = EBADF;
 +		return (-1);
 +	case FILE_TYPE_CHAR:
 +	case FILE_TYPE_PIPE:
 +		if (ftype == FILE_TYPE_CHAR) {
 +			st->st_mode = S_IFCHR;
 +			st->st_size = 0;
 +		} else {
 +			DWORD avail;
 +
 +			st->st_mode = S_IFIFO;
 +			if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL))
 +				st->st_size = avail;
 +			else
 +				st->st_size = 0;
 +		}
 +		st->st_atime = 0;
 +		st->st_atime_nsec = 0;
 +		st->st_mtime = 0;
 +		st->st_mtime_nsec = 0;
 +		st->st_ctime = 0;
 +		st->st_ctime_nsec = 0;
 +		st->st_ino = 0;
 +		st->st_nlink = 1;
 +		st->st_uid = 0;
 +		st->st_gid = 0;
 +		st->st_rdev = 0;
 +		st->st_dev = 0;
 +		return (0);
 +	case FILE_TYPE_DISK:
 +		break;
 +	default:
 +		/* This ftype is undocumented type. */
 +		la_dosmaperr(GetLastError());
 +		return (-1);
 +	}
 +
 +	ZeroMemory(&info, sizeof(info));
 +	if (!GetFileInformationByHandle (handle, &info)) {
 +		la_dosmaperr(GetLastError());
 +		return (-1);
 +	}
 +
 +	mode = S_IRUSR | S_IRGRP | S_IROTH;
 +	if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
 +		mode |= S_IWUSR | S_IWGRP | S_IWOTH;
 +	if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 +		mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
 +	else
 +		mode |= S_IFREG;
 +	st->st_mode = mode;
 +	
 +	fileTimeToUTC(&info.ftLastAccessTime, &time, &ns);
 +	st->st_atime = time; 
 +	st->st_atime_nsec = ns;
 +	fileTimeToUTC(&info.ftLastWriteTime, &time, &ns);
 +	st->st_mtime = time;
 +	st->st_mtime_nsec = ns;
 +	fileTimeToUTC(&info.ftCreationTime, &time, &ns);
 +	st->st_ctime = time;
 +	st->st_ctime_nsec = ns;
 +	st->st_size = 
 +	    ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1))
 +		+ (int64_t)(info.nFileSizeLow);
 +#ifdef SIMULATE_WIN_STAT
 +	st->st_ino = 0;
 +	st->st_nlink = 1;
 +	st->st_dev = 0;
 +#else
 +	/* Getting FileIndex as i-node. We should remove a sequence which
 +	 * is high-16-bits of nFileIndexHigh. */
 +	ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL;
 +	ino64.LowPart  = info.nFileIndexLow;
 +	st->st_ino = ino64.QuadPart;
 +	st->st_nlink = info.nNumberOfLinks;
 +	if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 +		++st->st_nlink;/* Add parent directory. */
 +	st->st_dev = info.dwVolumeSerialNumber;
 +#endif
 +	st->st_uid = 0;
 +	st->st_gid = 0;
 +	st->st_rdev = 0;
 +	return (0);
 +}
 +
 +static void
 +copy_stat(struct stat *st, struct ustat *us)
 +{
 +	st->st_atime = us->st_atime;
 +	st->st_ctime = us->st_ctime;
 +	st->st_mtime = us->st_mtime;
 +	st->st_gid = us->st_gid;
 +	st->st_ino = getino(us);
 +	st->st_mode = us->st_mode;
 +	st->st_nlink = us->st_nlink;
 +	st->st_size = us->st_size;
 +	st->st_uid = us->st_uid;
 +	st->st_dev = us->st_dev;
 +	st->st_rdev = us->st_rdev;
 +}
 +
 +/*
 + * TODO: Remove a use of __la_fstat and __la_stat.
 + * We should use GetFileInformationByHandle in place
 + * where We still use the *stat functions.
 + */
 +int
 +__la_fstat(int fd, struct stat *st)
 +{
 +	struct ustat u;
 +	int ret;
 +
 +	if (fd < 0) {
 +		errno = EBADF;
 +		return (-1);
 +	}
 +	ret = __hstat((HANDLE)_get_osfhandle(fd), &u);
 +	if (ret >= 0) {
 +		copy_stat(st, &u);
 +		if (u.st_mode & (S_IFCHR | S_IFIFO)) {
 +			st->st_dev = fd;
 +			st->st_rdev = fd;
 +		}
 +	}
 +	return (ret);
 +}
 +
 +/* This can exceed MAX_PATH limitation. */
 +int
 +__la_stat(const char *path, struct stat *st)
 +{
 +	HANDLE handle;
 +	struct ustat u;
 +	int ret;
 +
 +	handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING,
 +		FILE_FLAG_BACKUP_SEMANTICS,
 +		NULL);
 +	if (handle == INVALID_HANDLE_VALUE) {
 +		la_dosmaperr(GetLastError());
 +		return (-1);
 +	}
 +	ret = __hstat(handle, &u);
 +	CloseHandle(handle);
 +	if (ret >= 0) {
 +		char *p;
 +
 +		copy_stat(st, &u);
 +		p = strrchr(path, '.');
 +		if (p != NULL && strlen(p) == 4) {
 +			char exttype[4];
 +
 +			++ p;
 +			exttype[0] = toupper(*p++);
 +			exttype[1] = toupper(*p++);
 +			exttype[2] = toupper(*p++);
 +			exttype[3] = '\0';
 +			if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") ||
 +				!strcmp(exttype, "BAT") || !strcmp(exttype, "COM"))
 +				st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
 +		}
 +	}
 +	return (ret);
 +}
 +
 +/*
 + * This waitpid is limited implementation.
 + */
 +pid_t
 +__la_waitpid(pid_t wpid, int *status, int option)
 +{
 +	HANDLE child;
 +	DWORD cs, ret;
 +
 +	(void)option;/* UNUSED */
 +	*status = 0;
 +	child = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, wpid);
 +	if (child == NULL) {
 +		la_dosmaperr(GetLastError());
 +		return (-1);
 +	}
 +	ret = WaitForSingleObject(child, INFINITE);
 +	if (ret == WAIT_FAILED) {
 +		CloseHandle(child);
 +		la_dosmaperr(GetLastError());
 +		return (-1);
 +	}
 +	if (GetExitCodeProcess(child, &cs) == 0) {
 +		CloseHandle(child);
 +		la_dosmaperr(GetLastError());
 +		return (-1);
 +	}
 +	if (cs == STILL_ACTIVE)
 +		*status = 0x100;
 +	else
 +		*status = (int)(cs & 0xff);
 +	CloseHandle(child);
 +	return (wpid);
 +}
 +
 +ssize_t
 +__la_write(int fd, const void *buf, size_t nbytes)
 +{
 +	DWORD bytes_written;
 +
 +#ifdef _WIN64
 +	if (nbytes > UINT32_MAX)
 +		nbytes = UINT32_MAX;
 +#endif
 +	if (fd < 0) {
 +		errno = EBADF;
 +		return (-1);
 +	}
 +	if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes,
 +	    &bytes_written, NULL)) {
 +		DWORD lasterr;
 +
 +		lasterr = GetLastError();
 +		if (lasterr == ERROR_ACCESS_DENIED)
 +			errno = EBADF;
 +		else
 +			la_dosmaperr(lasterr);
 +		return (-1);
 +	}
 +	return (bytes_written);
 +}
 +
 +/*
 + * The following function was modified from PostgreSQL sources and is
 + * subject to the copyright below.
 + */
 +/*-------------------------------------------------------------------------
 + *
 + * win32error.c
 + *	  Map win32 error codes to errno values
 + *
 + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
 + *
 + * IDENTIFICATION
 + *	  $PostgreSQL: pgsql/src/port/win32error.c,v 1.4 2008/01/01 19:46:00 momjian Exp $
 + *
 + *-------------------------------------------------------------------------
 + */
 +/*
 +PostgreSQL Database Management System
 +(formerly known as Postgres, then as Postgres95)
 +
 +Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
 +
 +Portions Copyright (c) 1994, The Regents of the University of California
 +
 +Permission to use, copy, modify, and distribute this software and its
 +documentation for any purpose, without fee, and without a written agreement
 +is hereby granted, provided that the above copyright notice and this
 +paragraph and the following two paragraphs appear in all copies.
 +
 +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
 +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
 +DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
 +POSSIBILITY OF SUCH DAMAGE.
 +
 +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 +AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 +ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
 +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 +*/
 +
 +static const struct {
 +	DWORD		winerr;
 +	int		doserr;
 +} doserrors[] =
 +{
 +	{	ERROR_INVALID_FUNCTION, EINVAL	},
 +	{	ERROR_FILE_NOT_FOUND, ENOENT	},
 +	{	ERROR_PATH_NOT_FOUND, ENOENT	},
 +	{	ERROR_TOO_MANY_OPEN_FILES, EMFILE	},
 +	{	ERROR_ACCESS_DENIED, EACCES	},
 +	{	ERROR_INVALID_HANDLE, EBADF	},
 +	{	ERROR_ARENA_TRASHED, ENOMEM	},
 +	{	ERROR_NOT_ENOUGH_MEMORY, ENOMEM	},
 +	{	ERROR_INVALID_BLOCK, ENOMEM	},
 +	{	ERROR_BAD_ENVIRONMENT, E2BIG	},
 +	{	ERROR_BAD_FORMAT, ENOEXEC	},
 +	{	ERROR_INVALID_ACCESS, EINVAL	},
 +	{	ERROR_INVALID_DATA, EINVAL	},
 +	{	ERROR_INVALID_DRIVE, ENOENT	},
 +	{	ERROR_CURRENT_DIRECTORY, EACCES	},
 +	{	ERROR_NOT_SAME_DEVICE, EXDEV	},
 +	{	ERROR_NO_MORE_FILES, ENOENT	},
 +	{	ERROR_LOCK_VIOLATION, EACCES	},
 +	{	ERROR_SHARING_VIOLATION, EACCES	},
 +	{	ERROR_BAD_NETPATH, ENOENT	},
 +	{	ERROR_NETWORK_ACCESS_DENIED, EACCES	},
 +	{	ERROR_BAD_NET_NAME, ENOENT	},
 +	{	ERROR_FILE_EXISTS, EEXIST	},
 +	{	ERROR_CANNOT_MAKE, EACCES	},
 +	{	ERROR_FAIL_I24, EACCES	},
 +	{	ERROR_INVALID_PARAMETER, EINVAL	},
 +	{	ERROR_NO_PROC_SLOTS, EAGAIN	},
 +	{	ERROR_DRIVE_LOCKED, EACCES	},
 +	{	ERROR_BROKEN_PIPE, EPIPE	},
 +	{	ERROR_DISK_FULL, ENOSPC	},
 +	{	ERROR_INVALID_TARGET_HANDLE, EBADF	},
 +	{	ERROR_INVALID_HANDLE, EINVAL	},
 +	{	ERROR_WAIT_NO_CHILDREN, ECHILD	},
 +	{	ERROR_CHILD_NOT_COMPLETE, ECHILD	},
 +	{	ERROR_DIRECT_ACCESS_HANDLE, EBADF	},
 +	{	ERROR_NEGATIVE_SEEK, EINVAL	},
 +	{	ERROR_SEEK_ON_DEVICE, EACCES	},
 +	{	ERROR_DIR_NOT_EMPTY, ENOTEMPTY	},
 +	{	ERROR_NOT_LOCKED, EACCES	},
 +	{	ERROR_BAD_PATHNAME, ENOENT	},
 +	{	ERROR_MAX_THRDS_REACHED, EAGAIN	},
 +	{	ERROR_LOCK_FAILED, EACCES	},
 +	{	ERROR_ALREADY_EXISTS, EEXIST	},
 +	{	ERROR_FILENAME_EXCED_RANGE, ENOENT	},
 +	{	ERROR_NESTING_NOT_ALLOWED, EAGAIN	},
 +	{	ERROR_NOT_ENOUGH_QUOTA, ENOMEM	}
 +};
 +
 +void
 +__la_dosmaperr(unsigned long e)
 +{
 +	int			i;
 +
 +	if (e == 0)
 +	{
 +		errno = 0;
 +		return;
 +	}
 +
 +	for (i = 0; i < sizeof(doserrors); i++)
 +	{
 +		if (doserrors[i].winerr == e)
 +		{
 +			errno = doserrors[i].doserr;
 +			return;
 +		}
 +	}
 +
 +	/* fprintf(stderr, "unrecognized win32 error code: %lu", e); */
 +	errno = EINVAL;
 +	return;
 +}
 +
 +#endif /* _WIN32 && !__CYGWIN__ */
diff --cc Utilities/cmlibarchive/libarchive/archive_windows.h
index ac44192,0000000..c581af3
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_windows.h
+++ b/Utilities/cmlibarchive/libarchive/archive_windows.h
@@@ -1,298 -1,0 +1,297 @@@
 +/*-
 + * Copyright (c) 2009-2011 Michihiro NAKAJIMA
 + * Copyright (c) 2003-2006 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.
 + *
 + * $FreeBSD$
 + */
 +
 +#ifndef __LIBARCHIVE_BUILD
 +#error This header is only to be used internally to libarchive.
 +#endif
 +
 +/*
 + * TODO: A lot of stuff in here isn't actually used by libarchive and
 + * can be trimmed out.  Note that this file is used by libarchive and
 + * libarchive_test but nowhere else.  (But note that it gets compiled
 + * with many different Windows environments, including MinGW, Visual
 + * Studio, and Cygwin.  Significant changes should be tested in all three.)
 + */
 +
 +/*
 + * TODO: Don't use off_t in here.  Use __int64 instead.  Note that
 + * Visual Studio and the Windows SDK define off_t as 32 bits; Win32's
 + * more modern file handling APIs all use __int64 instead of off_t.
 + */
 +
 +#ifndef LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED
 +#define	LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED
 +
 +/* Start of configuration for native Win32  */
 +
 +#include <errno.h>
 +#define	set_errno(val)	((errno)=val)
 +#include <io.h>
 +#include <stdlib.h>   //brings in NULL
 +#if defined(HAVE_STDINT_H)
 +#include <stdint.h>
 +#endif
 +#include <stdio.h>
 +#include <fcntl.h>
 +#include <sys/stat.h>
 +#include <process.h>
 +#include <direct.h>
 +#if defined(__MINGW32__) && defined(HAVE_UNISTD_H)
 +/* Prevent build error from a type mismatch of ftruncate().
 + * This unistd.h defines it as ftruncate(int, off_t). */
 +#include <unistd.h>
 +#endif
 +#define NOCRYPT
 +#include <windows.h>
 +//#define	EFTYPE 7
 +
 +#if defined(_MSC_VER)
 +/* TODO: Fix the code, don't suppress the warnings. */
 +#pragma warning(push,1)
 +#pragma warning(disable:4761)   /* integral size mismatch in argument; conversion supplied */
 +#endif
 +#if defined(__BORLANDC__)
 +#pragma warn -8068	/* Constant out of range in comparison. */
 +#pragma warn -8072	/* Suspicious pointer arithmetic. */
 +#endif
 +
 +#ifndef NULL
 +#ifdef  __cplusplus
 +#define	NULL    0
 +#else
 +#define	NULL    ((void *)0)
 +#endif
 +#endif
 +
 +/* Alias the Windows _function to the POSIX equivalent. */
 +#define	close		_close
- #define	fcntl		__la_fcntl
++#define	fcntl(fd, cmd, flg)	/* No operation. */		
 +#ifndef fileno
 +#define	fileno		_fileno
 +#endif
 +#define	fstat		__la_fstat
 +#if !defined(__BORLANDC__)
 +#define	lseek		_lseeki64
 +#else
 +#define	lseek		__la_lseek
 +#define __LA_LSEEK_NEEDED
 +#endif
 +#define	lstat		__la_stat
 +#define	open		__la_open
 +#define	read		__la_read
 +#if !defined(__BORLANDC__)
 +#define setmode		_setmode
 +#endif
 +#define	stat(path,stref)		__la_stat(path,stref)
 +#if !defined(__BORLANDC__)
 +#define	strdup		_strdup
 +#endif
 +#define	tzset		_tzset
 +#if !defined(__BORLANDC__)
 +#define	umask		_umask
 +#endif
 +#define	waitpid		__la_waitpid
 +#define	write		__la_write
 +
 +#ifndef O_RDONLY
 +#define	O_RDONLY	_O_RDONLY
 +#define	O_WRONLY	_O_WRONLY
 +#define	O_TRUNC		_O_TRUNC
 +#define	O_CREAT		_O_CREAT
 +#define	O_EXCL		_O_EXCL
 +#define	O_BINARY	_O_BINARY
 +#endif
 +
 +#ifndef _S_IFIFO
 +  #define	_S_IFIFO        0010000   /* pipe */
 +#endif
 +#ifndef _S_IFCHR
 +  #define	_S_IFCHR        0020000   /* character special */
 +#endif
 +#ifndef _S_IFDIR
 +  #define	_S_IFDIR        0040000   /* directory */
 +#endif
 +#ifndef _S_IFBLK
 +  #define	_S_IFBLK        0060000   /* block special */
 +#endif
 +#ifndef _S_IFLNK
 +  #define	_S_IFLNK        0120000   /* symbolic link */
 +#endif
 +#ifndef _S_IFSOCK
 +  #define	_S_IFSOCK       0140000   /* socket */
 +#endif
 +#ifndef	_S_IFREG
 +  #define	_S_IFREG        0100000   /* regular */
 +#endif
 +#ifndef	_S_IFMT
 +  #define	_S_IFMT         0170000   /* file type mask */
 +#endif
 +
 +#ifndef S_IFIFO
 +#define	S_IFIFO     _S_IFIFO
 +#endif
 +//#define	S_IFCHR  _S_IFCHR
 +//#define	S_IFDIR  _S_IFDIR
 +#ifndef S_IFBLK
 +#define	S_IFBLK     _S_IFBLK
 +#endif
 +#ifndef S_IFLNK
 +#define	S_IFLNK     _S_IFLNK
 +#endif
 +#ifndef S_IFSOCK
 +#define	S_IFSOCK    _S_IFSOCK
 +#endif
 +//#define	S_IFREG  _S_IFREG
 +//#define	S_IFMT   _S_IFMT
 +
 +#ifndef S_ISBLK
 +#define	S_ISBLK(m)	(((m) & S_IFMT) == S_IFBLK)	/* block special */
 +#define	S_ISFIFO(m)	(((m) & S_IFMT) == S_IFIFO)	/* fifo or socket */
 +#define	S_ISCHR(m)	(((m) & S_IFMT) == S_IFCHR)	/* char special */
 +#define	S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)	/* directory */
 +#define	S_ISREG(m)	(((m) & S_IFMT) == S_IFREG)	/* regular file */
 +#endif
 +#define	S_ISLNK(m)  (((m) & S_IFMT) == S_IFLNK) /* Symbolic link */
 +#define	S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* Socket */
 +
 +#define	_S_ISUID        0004000   /* set user id on execution */
 +#define	_S_ISGID        0002000   /* set group id on execution */
 +#define	_S_ISVTX        0001000   /* save swapped text even after use */
 +
 +#define	S_ISUID        _S_ISUID
 +#define	S_ISGID        _S_ISGID
 +#define	S_ISVTX        _S_ISVTX
 +
 +#define	_S_IRWXU	     (_S_IREAD | _S_IWRITE | _S_IEXEC)
 +#define	_S_IXUSR	     _S_IEXEC  /* read permission, user */
 +#define	_S_IWUSR	     _S_IWRITE /* write permission, user */
 +#define	_S_IRUSR	     _S_IREAD  /* execute/search permission, user */
 +#define	_S_IRWXG        (_S_IRWXU >> 3)
 +#define	_S_IXGRP        (_S_IXUSR >> 3) /* read permission, group */
 +#define	_S_IWGRP        (_S_IWUSR >> 3) /* write permission, group */
 +#define	_S_IRGRP        (_S_IRUSR >> 3) /* execute/search permission, group */
 +#define	_S_IRWXO        (_S_IRWXG >> 3) 
 +#define	_S_IXOTH        (_S_IXGRP >> 3) /* read permission, other */
 +#define	_S_IWOTH        (_S_IWGRP >> 3) /* write permission, other */
 +#define	_S_IROTH        (_S_IRGRP  >> 3) /* execute/search permission, other */
 +
 +#ifndef S_IRWXU
 +#define	S_IRWXU	     _S_IRWXU
 +#define	S_IXUSR	     _S_IXUSR
 +#define	S_IWUSR	     _S_IWUSR
 +#define	S_IRUSR	     _S_IRUSR
 +#endif
 +#define	S_IRWXG        _S_IRWXG
 +#define	S_IXGRP        _S_IXGRP
 +#define	S_IWGRP        _S_IWGRP
 +#define	S_IRGRP        _S_IRGRP
 +#define	S_IRWXO        _S_IRWXO
 +#define	S_IXOTH        _S_IXOTH
 +#define	S_IWOTH        _S_IWOTH
 +#define	S_IROTH        _S_IROTH
 +
 +#define	F_DUPFD	  	0	/* Duplicate file descriptor.  */
 +#define	F_GETFD		1	/* Get file descriptor flags.  */
 +#define	F_SETFD		2	/* Set file descriptor flags.  */
 +#define	F_GETFL		3	/* Get file status flags.  */
 +#define	F_SETFL		4	/* Set file status flags.  */
 +#define	F_GETOWN		5	/* Get owner (receiver of SIGIO).  */
 +#define	F_SETOWN		6	/* Set owner (receiver of SIGIO).  */
 +#define	F_GETLK		7	/* Get record locking info.  */
 +#define	F_SETLK		8	/* Set record locking info (non-blocking).  */
 +#define	F_SETLKW		9	/* Set record locking info (blocking).  */
 +
 +/* XXX missing */
 +#define	F_GETLK64	7	/* Get record locking info.  */
 +#define	F_SETLK64	8	/* Set record locking info (non-blocking).  */
 +#define	F_SETLKW64	9	/* Set record locking info (blocking).  */
 +
 +/* File descriptor flags used with F_GETFD and F_SETFD.  */
 +#define	FD_CLOEXEC	1	/* Close on exec.  */
 +
 +//NOT SURE IF O_NONBLOCK is OK here but at least the 0x0004 flag is not used by anything else...
 +#define	O_NONBLOCK 0x0004 /* Non-blocking I/O.  */
 +//#define	O_NDELAY   O_NONBLOCK
 +
 +/* Symbolic constants for the access() function */
 +#if !defined(F_OK)
 +    #define	R_OK    4       /*  Test for read permission    */
 +    #define	W_OK    2       /*  Test for write permission   */
 +    #define	X_OK    1       /*  Test for execute permission */
 +    #define	F_OK    0       /*  Test for existence of file  */
 +#endif
 +
 +
 +/* Replacement POSIX function */
- extern int	 __la_fcntl(int fd, int cmd, int val);
 +extern int	 __la_fstat(int fd, struct stat *st);
 +extern int	 __la_lstat(const char *path, struct stat *st);
 +#if defined(__LA_LSEEK_NEEDED)
 +extern __int64	 __la_lseek(int fd, __int64 offset, int whence);
 +#endif
 +extern int	 __la_open(const char *path, int flags, ...);
 +extern ssize_t	 __la_read(int fd, void *buf, size_t nbytes);
 +extern int	 __la_stat(const char *path, struct stat *st);
 +extern pid_t	 __la_waitpid(pid_t wpid, int *status, int option);
 +extern ssize_t	 __la_write(int fd, const void *buf, size_t nbytes);
 +
 +#define _stat64i32(path, st)	__la_stat(path, st)
 +#define _stat64(path, st)	__la_stat(path, st)
 +/* for status returned by la_waitpid */
 +#define WIFEXITED(sts)		((sts & 0x100) == 0)
 +#define WEXITSTATUS(sts)	(sts & 0x0FF)
 +
 +extern wchar_t *__la_win_permissive_name(const char *name);
 +extern wchar_t *__la_win_permissive_name_w(const wchar_t *wname);
 +extern void __la_dosmaperr(unsigned long e);
 +#define la_dosmaperr(e) __la_dosmaperr(e)
 +
 +#if defined(HAVE_WCRTOMB) && defined(__BORLANDC__)
 +typedef int mbstate_t;
 +size_t wcrtomb(char *, wchar_t, mbstate_t *);
 +#endif
 +
 +#if defined(_MSC_VER) && _MSC_VER < 1300
 +WINBASEAPI BOOL WINAPI GetVolumePathNameW(
 +	LPCWSTR lpszFileName,
 +	LPWSTR lpszVolumePathName,
 +	DWORD cchBufferLength
 +	);
 +# if _WIN32_WINNT < 0x0500 /* windows.h not providing 0x500 API */
 +typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
 +	LARGE_INTEGER FileOffset;
 +	LARGE_INTEGER Length;
 +} FILE_ALLOCATED_RANGE_BUFFER, *PFILE_ALLOCATED_RANGE_BUFFER;
 +#  define FSCTL_SET_SPARSE \
 +     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_WRITE_DATA)
 +#  define FSCTL_QUERY_ALLOCATED_RANGES \
 +     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51,  METHOD_NEITHER, FILE_READ_DATA)
 +# endif
 +#endif
 +
 +#endif /* LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED */
diff --cc Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
index 0e5f5ce,0000000..ce3298b
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
@@@ -1,2275 -1,0 +1,2303 @@@
 +/*-
 + * 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
 +#include <stdlib.h>
 +#ifdef HAVE_BZLIB_H
 +#include <bzlib.h>
 +#endif
 +#if HAVE_LZMA_H
 +#include <lzma.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#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_rb.h"
 +#include "archive_string.h"
 +#include "archive_write_private.h"
 +
 +/*
 + * Codec ID
 + */
 +#define _7Z_COPY	0
 +#define _7Z_LZMA1	0x030101
 +#define _7Z_LZMA2	0x21
 +#define _7Z_DEFLATE	0x040108
 +#define _7Z_BZIP2	0x040202
 +#define _7Z_PPMD	0x030401
 +
 +/*
 + * 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
 +
 +enum la_zaction {
 +	ARCHIVE_Z_FINISH,
 +	ARCHIVE_Z_RUN
 +};
 +
 +/*
-  * Universal zstream.
++ * A stream object of universal compressor.
 + */
 +struct la_zstream {
 +	const uint8_t		*next_in;
 +	size_t			 avail_in;
 +	uint64_t		 total_in;
 +
 +	uint8_t			*next_out;
 +	size_t			 avail_out;
 +	uint64_t		 total_out;
 +
 +	uint32_t		 prop_size;
 +	uint8_t			*props;
 +
 +	int			 valid;
 +	void			*real_stream;
 +	int			 (*code) (struct archive *a,
 +				    struct la_zstream *lastrm,
 +				    enum la_zaction action);
 +	int			 (*end)(struct archive *a,
 +				    struct la_zstream *lastrm);
 +};
 +
 +#define PPMD7_DEFAULT_ORDER	6
 +#define PPMD7_DEFAULT_MEM_SIZE	(1 << 24)
 +
 +struct ppmd_stream {
 +	int			 stat;
 +	CPpmd7			 ppmd7_context;
 +	CPpmd7z_RangeEnc	 range_enc;
 +	IByteOut		 byteout;
 +	uint8_t			*buff;
 +	uint8_t			*buff_ptr;
 +	uint8_t			*buff_end;
 +	size_t			 buff_bytes;
 +};
 +
 +struct coder {
 +	unsigned		 codec;
 +	size_t			 prop_size;
 +	uint8_t			*props;
 +};
 +
 +struct file {
 +	struct archive_rb_node	 rbnode;
 +
 +	struct file		*next;
 +	unsigned		 name_len;
 +	uint8_t			*utf16name;/* UTF16-LE name. */
 +	uint64_t		 size;
 +	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)
 +
 +	struct {
- 		time_t			 time;
- 		long			 time_ns;
++		time_t		 time;
++		long		 time_ns;
 +	}			 times[3];
 +#define MTIME 0
 +#define ATIME 1
 +#define CTIME 2
 +
 +	mode_t			 mode;
 +	uint32_t		 crc32;
 +
 +	int			 dir:1;
 +};
 +
 +struct _7zip {
 +	int			 temp_fd;
 +	uint64_t		 temp_offset;
 +
 +	struct file		*cur_file;
 +	size_t			 total_number_entry;
 +	size_t			 total_number_nonempty_entry;
 +	size_t			 total_number_empty_entry;
 +	size_t			 total_number_dir_entry;
 +	size_t			 total_bytes_entry_name;
 +	size_t			 total_number_time_defined[3];
 +	uint64_t		 total_bytes_compressed;
 +	uint64_t		 total_bytes_uncompressed;
 +	uint64_t		 entry_bytes_remaining;
 +	uint32_t		 entry_crc32;
 +	uint32_t		 precode_crc32;
 +	uint32_t		 encoded_crc32;
 +	int			 crc32flg;
 +#define	PRECODE_CRC32	1
 +#define	ENCODED_CRC32	2
 +
 +	unsigned		 opt_compression;
 +	int			 opt_compression_level;
 +
 +	struct la_zstream	 stream;
 +	struct coder		 coder;
 +
 +	struct archive_string_conv *sconv;
 +
 +	/*
 +	 * Compressed data buffer.
 +	 */
 +	unsigned char		 wbuff[1024 * 64];
 +	size_t			 wbuff_remaining;
 +
 +	/*
 +	 * The list of the file entries which has its contents is used to
 +	 * manage struct file objects.
 +	 * We use 'next' a menber of struct file to chain.
 +	 */
 +	struct {
 +		struct file	*first;
 +		struct file	**last;
 +	}			 file_list, empty_list;
 +	struct archive_rb_tree	 rbtree;/* for empty files */
 +};
 +
 +static int	_7z_options(struct archive_write *,
 +		    const char *, const char *);
 +static int	_7z_write_header(struct archive_write *,
 +		    struct archive_entry *);
 +static ssize_t	_7z_write_data(struct archive_write *,
 +		    const void *, size_t);
 +static int	_7z_finish_entry(struct archive_write *);
 +static int	_7z_close(struct archive_write *);
 +static int	_7z_free(struct archive_write *);
 +static int	file_cmp_node(const struct archive_rb_node *,
 +		    const struct archive_rb_node *);
 +static int	file_cmp_key(const struct archive_rb_node *, const void *);
 +static int	file_new(struct archive_write *a, struct archive_entry *,
 +		    struct file **);
 +static void	file_free(struct file *);
 +static void	file_register(struct _7zip *, struct file *);
 +static void	file_register_empty(struct _7zip *, struct file *);
 +static void	file_init_register(struct _7zip *);
 +static void	file_init_register_empty(struct _7zip *);
 +static void	file_free_register(struct _7zip *);
 +static ssize_t	compress_out(struct archive_write *, const void *, size_t ,
 +		    enum la_zaction);
 +static int	compression_init_encoder_copy(struct archive *,
 +		    struct la_zstream *);
 +static int	compression_code_copy(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_copy(struct archive *, struct la_zstream *);
 +static int	compression_init_encoder_deflate(struct archive *,
 +		    struct la_zstream *, int, int);
 +#ifdef HAVE_ZLIB_H
 +static int	compression_code_deflate(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_deflate(struct archive *, struct la_zstream *);
 +#endif
 +static int	compression_init_encoder_bzip2(struct archive *,
 +		    struct la_zstream *, int);
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +static int	compression_code_bzip2(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_bzip2(struct archive *, struct la_zstream *);
 +#endif
 +static int	compression_init_encoder_lzma1(struct archive *,
 +		    struct la_zstream *, int);
 +static int	compression_init_encoder_lzma2(struct archive *,
 +		    struct la_zstream *, int);
 +#if defined(HAVE_LZMA_H)
 +static int	compression_code_lzma(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_lzma(struct archive *, struct la_zstream *);
 +#endif
 +static int	compression_init_encoder_ppmd(struct archive *,
 +		    struct la_zstream *, unsigned, uint32_t);
 +static int	compression_code_ppmd(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_ppmd(struct archive *, struct la_zstream *);
 +static int	_7z_compression_init_encoder(struct archive_write *, unsigned,
 +		    int);
 +static int	compression_code(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end(struct archive *,
 +		    struct la_zstream *);
 +static int	enc_uint64(struct archive_write *, uint64_t);
 +static int	make_header(struct archive_write *, uint64_t, uint64_t,
 +		    uint64_t, int, struct coder *);
 +static int	make_streamsInfo(struct archive_write *, uint64_t, uint64_t,
 +		    	uint64_t, int, struct coder *, int, uint32_t);
 +
 +int
 +archive_write_set_format_7zip(struct archive *_a)
 +{
 +	static const struct archive_rb_tree_ops rb_ops = {
 +		file_cmp_node, file_cmp_key
 +	};
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct _7zip *zip;
 +
 +	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_write_set_format_7zip");
 +
 +	/* If another format was already registered, unregister it. */
 +	if (a->format_free != NULL)
 +		(a->format_free)(a);
 +
 +	zip = calloc(1, sizeof(*zip));
 +	if (zip == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate 7-Zip data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	zip->temp_fd = -1;
 +	__archive_rb_tree_init(&(zip->rbtree), &rb_ops);
 +	file_init_register(zip);
 +	file_init_register_empty(zip);
 +
 +	/* Set default compression type and its level. */
 +#if HAVE_LZMA_H
 +	zip->opt_compression = _7Z_LZMA1;
 +#elif defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +	zip->opt_compression = _7Z_BZIP2;
 +#elif defined(HAVE_ZLIB_H)
 +	zip->opt_compression = _7Z_DEFLATE;
 +#else
 +	zip->opt_compression = _7Z_COPY;
 +#endif
 +	zip->opt_compression_level = 6;
 +
 +	a->format_data = zip;
 +
 +	a->format_name = "7zip";
 +	a->format_options = _7z_options;
 +	a->format_write_header = _7z_write_header;
 +	a->format_write_data = _7z_write_data;
 +	a->format_finish_entry = _7z_finish_entry;
 +	a->format_close = _7z_close;
 +	a->format_free = _7z_free;
 +	a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
 +	a->archive.archive_format_name = "7zip";
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +_7z_options(struct archive_write *a, const char *key, const char *value)
 +{
 +	struct _7zip *zip;
 +
 +	zip = (struct _7zip *)a->format_data;
 +
 +	if (strcmp(key, "compression") == 0) {
 +		const char *name = NULL;
 +
 +		if (value == NULL || strcmp(value, "copy") == 0 ||
 +		    strcmp(value, "COPY") == 0 ||
 +		    strcmp(value, "store") == 0 ||
 +		    strcmp(value, "STORE") == 0)
 +			zip->opt_compression = _7Z_COPY;
 +		else if (strcmp(value, "deflate") == 0 ||
 +		    strcmp(value, "DEFLATE") == 0)
 +#if HAVE_ZLIB_H
 +			zip->opt_compression = _7Z_DEFLATE;
 +#else
 +			name = "deflate";
 +#endif
 +		else if (strcmp(value, "bzip2") == 0 ||
 +		    strcmp(value, "BZIP2") == 0)
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +			zip->opt_compression = _7Z_BZIP2;
 +#else
 +			name = "bzip2";
 +#endif
 +		else if (strcmp(value, "lzma1") == 0 ||
 +		    strcmp(value, "LZMA1") == 0)
 +#if HAVE_LZMA_H
 +			zip->opt_compression = _7Z_LZMA1;
 +#else
 +			name = "lzma1";
 +#endif
 +		else if (strcmp(value, "lzma2") == 0 ||
 +		    strcmp(value, "LZMA2") == 0)
 +#if HAVE_LZMA_H
 +			zip->opt_compression = _7Z_LZMA2;
 +#else
 +			name = "lzma2";
 +#endif
 +		else if (strcmp(value, "ppmd") == 0 ||
 +		    strcmp(value, "PPMD") == 0 ||
 +		    strcmp(value, "PPMd") == 0)
 +			zip->opt_compression = _7Z_PPMD;
 +		else {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Unkonwn compression name: `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		if (name != NULL) {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "`%s' compression not supported "
 +			    "on this platform",
 +			    name);
 +			return (ARCHIVE_FAILED);
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +	if (strcmp(key, "compression-level") == 0) {
 +		if (value == NULL ||
 +		    !(value[0] >= '0' && value[0] <= '9') ||
 +		    value[1] != '\0') {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Illeagal value `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		zip->opt_compression_level = value[0] - '0';
 +		return (ARCHIVE_OK);
 +	}
 +
 +	return (ARCHIVE_FAILED);
 +}
 +
 +static int
 +_7z_write_header(struct archive_write *a, struct archive_entry *entry)
 +{
 +	struct _7zip *zip;
 +	struct file *file;
 +	int r;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	zip->cur_file = NULL;
 +	zip->entry_bytes_remaining = 0;
 +
 +	if (zip->sconv == NULL) {
 +		zip->sconv = archive_string_conversion_to_charset(
 +		    &a->archive, "UTF-16LE", 1);
 +		if (zip->sconv == NULL)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	r = file_new(a, entry, &file);
 +	if (r < ARCHIVE_WARN) {
 +		file_free(file);
 +		return (r);
 +	}
 +
 +	if (file->flg & MTIME_IS_SET)
 +		zip->total_number_time_defined[MTIME]++;
 +	if (file->flg & CTIME_IS_SET)
 +		zip->total_number_time_defined[CTIME]++;
 +	if (file->flg & ATIME_IS_SET)
 +		zip->total_number_time_defined[ATIME]++;
 +
 +	if (file->size == 0 && file->dir) {
 +		if (!__archive_rb_tree_insert_node(&(zip->rbtree),
 +		    (struct archive_rb_node *)file))
 +			file_free(file);
 +	}
 +	zip->total_number_entry++;
 +	zip->total_bytes_entry_name += file->name_len + 2;
 +	if (file->size == 0) {
++		/* Count up the number of empty files. */
 +		zip->total_number_empty_entry++;
 +		if (file->dir)
 +			zip->total_number_dir_entry++;
 +		else
 +			file_register_empty(zip, file);
 +		return (r);
 +	}
 +
 +	/*
 +	 * Init compression.
 +	 */
 +	if ((zip->total_number_entry - zip->total_number_empty_entry) == 1) {
 +		r = _7z_compression_init_encoder(a, zip->opt_compression,
 +			zip->opt_compression_level);
 +		if (r < 0) {
 +			file_free(file);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	/* Register a non-empty file. */
 +	file_register(zip, file);
 +
 +	/*
 +	 * Set the current file to cur_file to read its contents.
 +	 */
 +	zip->cur_file = file;
 +
 +
 +	/* Save a offset of current file in temporary file. */
 +	zip->entry_bytes_remaining = file->size;
 +	zip->entry_crc32 = 0;
 +
++	/*
++	 * Store a symbolic link name as file contents.
++	 */
 +	if (archive_entry_filetype(entry) == AE_IFLNK) {
 +		ssize_t bytes;
 +		const void *p = (const void *)archive_entry_symlink(entry);
 +		bytes = compress_out(a, p, file->size, ARCHIVE_Z_RUN);
 +		if (bytes < 0)
 +			return ((int)bytes);
 +		zip->entry_crc32 = crc32(zip->entry_crc32, p, bytes);
 +		zip->entry_bytes_remaining -= bytes;
 +	}
 +
 +	return (r);
 +}
 +
++/*
++ * Write data to a temporary file.
++ */
 +static int
 +write_to_temp(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct _7zip *zip;
 +	unsigned char *p;
 +	ssize_t ws;
 +
 +	zip = (struct _7zip *)a->format_data;
 +
 +	/*
 +	 * Open a temporary file.
 +	 */
 +	if (zip->temp_fd == -1) {
 +		zip->temp_offset = 0;
 +		zip->temp_fd = __archive_mktemp(NULL);
 +		if (zip->temp_fd < 0) {
 +			archive_set_error(&a->archive, errno,
 +			    "Couldn't create temporary file");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	p = (unsigned char *)buff;
 +	while (s) {
 +		ws = write(zip->temp_fd, p, s);
 +		if (ws < 0) {
 +			archive_set_error(&(a->archive), errno,
 +			    "fwrite function failed");
 +			return (ARCHIVE_FATAL);
 +		}
 +		s -= ws;
 +		p += ws;
 +		zip->temp_offset += ws;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static ssize_t
 +compress_out(struct archive_write *a, const void *buff, size_t s,
 +    enum la_zaction run)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +	int r;
 +
 +	if (run == ARCHIVE_Z_FINISH && zip->stream.total_in == 0 && s == 0)
 +		return (0);
 +
 +	if ((zip->crc32flg & PRECODE_CRC32) && s)
 +		zip->precode_crc32 = crc32(zip->precode_crc32, buff, s);
 +	zip->stream.next_in = (const unsigned char *)buff;
 +	zip->stream.avail_in = s;
 +	do {
 +		/* Compress file data. */
 +		r = compression_code(&(a->archive), &(zip->stream), run);
 +		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
 +			return (ARCHIVE_FATAL);
 +		if (zip->stream.avail_out == 0) {
 +			if (write_to_temp(a, zip->wbuff, sizeof(zip->wbuff))
 +			    != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			zip->stream.next_out = zip->wbuff;
 +			zip->stream.avail_out = sizeof(zip->wbuff);
 +			if (zip->crc32flg & ENCODED_CRC32)
 +				zip->encoded_crc32 = crc32(zip->encoded_crc32,
 +				    zip->wbuff, sizeof(zip->wbuff));
 +		}
 +	} while (zip->stream.avail_in);
 +	if (run == ARCHIVE_Z_FINISH) {
 +		uint64_t bytes = sizeof(zip->wbuff) - zip->stream.avail_out;
 +		if (write_to_temp(a, zip->wbuff, bytes) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		if ((zip->crc32flg & ENCODED_CRC32) && bytes)
 +			zip->encoded_crc32 = crc32(zip->encoded_crc32,
 +			    zip->wbuff, bytes);
 +	}
 +
 +	return (s);
 +}
 +
 +static ssize_t
 +_7z_write_data(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct _7zip *zip;
 +	ssize_t bytes;
 +
 +	zip = (struct _7zip *)a->format_data;
 +
 +	if (s > zip->entry_bytes_remaining)
 +		s = zip->entry_bytes_remaining;
 +	if (s == 0 || zip->cur_file == NULL)
 +		return (0);
 +	bytes = compress_out(a, buff, s, ARCHIVE_Z_RUN);
 +	if (bytes < 0)
 +		return (bytes);
 +	zip->entry_crc32 = crc32(zip->entry_crc32, buff, bytes);
 +	zip->entry_bytes_remaining -= bytes;
 +	return (bytes);
 +}
 +
 +static int
 +_7z_finish_entry(struct archive_write *a)
 +{
 +	struct _7zip *zip;
 +	size_t s;
 +	ssize_t r;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	if (zip->cur_file == NULL)
 +		return (ARCHIVE_OK);
 +
 +	while (zip->entry_bytes_remaining > 0) {
 +		s = zip->entry_bytes_remaining;
 +		if (s > a->null_length)
 +			s = a->null_length;
 +		r = _7z_write_data(a, a->nulls, s);
 +		if (r < 0)
 +			return (r);
 +	}
 +	zip->total_bytes_compressed += zip->stream.total_in;
 +	zip->total_bytes_uncompressed += zip->stream.total_out;
 +	zip->cur_file->crc32 = zip->entry_crc32;
 +	zip->cur_file = NULL;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +flush_wbuff(struct archive_write *a)
 +{
 +	struct _7zip *zip;
 +	int r;
 +	size_t s;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	s = sizeof(zip->wbuff) - zip->wbuff_remaining;
 +	r = __archive_write_output(a, zip->wbuff, s);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	zip->wbuff_remaining = sizeof(zip->wbuff);
 +	return (r);
 +}
 +
 +static int
 +copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
 +{
 +	struct _7zip *zip;
 +	int r;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	if (zip->temp_offset > 0 &&
 +	    lseek(zip->temp_fd, offset, SEEK_SET) < 0) {
 +		archive_set_error(&(a->archive), errno, "lseek failed");
 +		return (ARCHIVE_FATAL);
 +	}
 +	while (length) {
 +		size_t rsize;
 +		ssize_t rs;
 +		unsigned char *wb;
 +
 +		if (length > zip->wbuff_remaining)
 +			rsize = zip->wbuff_remaining;
 +		else
 +			rsize = (size_t)length;
 +		wb = zip->wbuff + (sizeof(zip->wbuff) - zip->wbuff_remaining);
 +		rs = read(zip->temp_fd, wb, rsize);
 +		if (rs < 0) {
 +			archive_set_error(&(a->archive), errno,
 +			    "Can't read temporary file(%jd)",
 +			    (intmax_t)rs);
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (rs == 0) {
 +			archive_set_error(&(a->archive), 0,
 +			    "Truncated 7-Zip archive");
 +			return (ARCHIVE_FATAL);
 +		}
 +		zip->wbuff_remaining -= rs;
 +		length -= rs;
 +		if (zip->wbuff_remaining == 0) {
 +			r = flush_wbuff(a);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +		}
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +_7z_close(struct archive_write *a)
 +{
 +	struct _7zip *zip;
 +	unsigned char *wb;
 +	uint64_t header_offset, header_size, header_unpacksize;
 +	uint64_t length;
 +	uint32_t header_crc32;
 +	int r;
 +
 +	zip = (struct _7zip *)a->format_data;
 +
 +	if (zip->total_number_entry > 0) {
 +		struct archive_rb_node *n;
 +		uint64_t data_offset, data_size, data_unpacksize;
 +		unsigned header_compression;
 +
 +		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
 +		if (r < 0)
 +			return (r);
 +		data_offset = 0;
 +		data_size = zip->stream.total_out;
 +		data_unpacksize = zip->stream.total_in;
 +		zip->coder.codec = zip->opt_compression;
 +		zip->coder.prop_size = zip->stream.prop_size;
 +		zip->coder.props = zip->stream.props;
 +		zip->stream.prop_size = 0;
 +		zip->stream.props = NULL;
 +		zip->total_number_nonempty_entry =
 +		    zip->total_number_entry - zip->total_number_empty_entry;
 +
++		/* Connect an empty file list. */
 +		*zip->file_list.last = zip->empty_list.first;
 +		zip->file_list.last = zip->empty_list.last;
++		/* Connect a directory file list. */
 +		ARCHIVE_RB_TREE_FOREACH(n, &(zip->rbtree)) {
 +			file_register(zip, (struct file *)n);
 +		}
 +
 +		/*
 +		 * NOTE: 7z command supports just LZMA1, LZMA2 and COPY for
- 		 * the header.
++		 * the compression type for encoding the header.
 +		 */
 +#if HAVE_LZMA_H
 +		header_compression = _7Z_LZMA1;
- 		/* If the stored file is only one, do not encode the header. */
++		/* If the stored file is only one, do not encode the header.
++		 * This is the same way 7z command does. */
 +		if (zip->total_number_entry == 1)
 +			header_compression = _7Z_COPY;
 +#else
 +		header_compression = _7Z_COPY;
 +#endif
 +		r = _7z_compression_init_encoder(a, header_compression, 6);
 +		if (r < 0)
 +			return (r);
 +		zip->crc32flg = PRECODE_CRC32;
 +		zip->precode_crc32 = 0;
 +		r = make_header(a, data_offset, data_size, data_unpacksize,
 +			1, &(zip->coder));
 +		if (r < 0)
 +			return (r);
 +		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
 +		if (r < 0)
 +			return (r);
 +		header_offset = data_offset + data_size;
 +		header_size = zip->stream.total_out;
 +		header_crc32 = zip->precode_crc32;
 +		header_unpacksize = zip->stream.total_in;
 +
 +		if (header_compression != _7Z_COPY) {
 +			/*
 +			 * Encode the header in order to reduce the size
 +			 * of the archive.
 +			 */
 +			free(zip->coder.props);
 +			zip->coder.codec = header_compression;
 +			zip->coder.prop_size = zip->stream.prop_size;
 +			zip->coder.props = zip->stream.props;
 +			zip->stream.prop_size = 0;
 +			zip->stream.props = NULL;
 +
 +			r = _7z_compression_init_encoder(a, _7Z_COPY, 0);
 +			if (r < 0)
 +				return (r);
 +			zip->crc32flg = ENCODED_CRC32;
 +			zip->encoded_crc32 = 0;
 +
 +			/*
 +			 * Make EncodedHeader.
 +			 */
 +			r = enc_uint64(a, kEncodedHeader);
 +			if (r < 0)
 +				return (r);
 +			r = make_streamsInfo(a, header_offset, header_size,
 +			      header_unpacksize, 1, &(zip->coder), 0,
 +			      header_crc32);
 +			if (r < 0)
 +				return (r);
 +			r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
 +			if (r < 0)
 +				return (r);
 +			header_offset = header_offset + header_size;
 +			header_size = zip->stream.total_out;
 +			header_crc32 = zip->encoded_crc32;
 +		}
 +		zip->crc32flg = 0;
 +	} else {
 +		header_offset = header_size = 0;
 +		header_crc32 = 0;
 +	}
 +	
 +	length = zip->temp_offset;
 +
 +	/*
 +	 * Make the zip header on wbuff(write buffer).
 +	 */
 +	wb = zip->wbuff;
 +	zip->wbuff_remaining = sizeof(zip->wbuff);
 +	memcpy(&wb[0], "7z\xBC\xAF\x27\x1C", 6);
 +	wb[6] = 0;/* Major version. */
 +	wb[7] = 3;/* Minor version. */
 +	archive_le64enc(&wb[12], header_offset);/* Next Header Offset */
 +	archive_le64enc(&wb[20], header_size);/* Next Header Size */
 +	archive_le32enc(&wb[28], header_crc32);/* Next Header CRC */
 +	archive_le32enc(&wb[8], crc32(0, &wb[12], 20));/* Start Header CRC */
 +	zip->wbuff_remaining -= 32;
 +
 +	/*
 +	 * Read all file contents and an encoded header from the temporary
 +	 * file and write out it.
 +	 */
 +	r = copy_out(a, 0, length);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	r = flush_wbuff(a);
 +	return (r);
 +}
 +
++/*
++ * Encode 64 bits value into 7-Zip's encoded UINT64 value.
++ */
 +static int
 +enc_uint64(struct archive_write *a, uint64_t val)
 +{
 +	unsigned mask = 0x80;
 +	uint8_t numdata[9];
 +	int i;
 +
 +	numdata[0] = 0;
 +	for (i = 1; i < sizeof(numdata); i++) {
 +		if (val < mask) {
 +			numdata[0] |= (uint8_t)val;
 +			break;
 +		}
 +		numdata[i] = (uint8_t)val;
 +		val >>= 8;
 +		numdata[0] |= mask;
 +		mask >>= 1;
 +	}
 +	return (compress_out(a, numdata, i, ARCHIVE_Z_RUN));
 +}
 +
 +static int
 +make_substreamsInfo(struct archive_write *a, struct coder *coders)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +	struct file *file;
 +	int r;
 +
 +	/*
 +	 * Make SubStreamsInfo.
 +	 */
 +	r = enc_uint64(a, kSubStreamsInfo);
 +	if (r < 0)
 +		return (r);
 +
 +	if (zip->total_number_nonempty_entry > 1 && coders->codec != _7Z_COPY) {
 +		/*
 +		 * Make NumUnPackStream.
 +		 */
 +		r = enc_uint64(a, kNumUnPackStream);
 +		if (r < 0)
 +			return (r);
 +
 +		/* Write numUnpackStreams */
 +		r = enc_uint64(a, zip->total_number_nonempty_entry);
 +		if (r < 0)
 +			return (r);
 +
 +		/*
 +		 * Make kSize.
 +		 */
 +		r = enc_uint64(a, kSize);
 +		if (r < 0)
 +			return (r);
 +		file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->next == NULL ||
 +			    file->next->size == 0)
 +				break;
 +			r = enc_uint64(a, file->size);
 +			if (r < 0)
 +				return (r);
 +		}
 +	}
 +
 +	/*
 +	 * Make CRC.
 +	 */
 +	r = enc_uint64(a, kCRC);
 +	if (r < 0)
 +		return (r);
 +
 +
 +	/* All are defined */
 +	r = enc_uint64(a, 1);
 +	if (r < 0)
 +		return (r);
 +	file = zip->file_list.first;
 +	for (;file != NULL; file = file->next) {
 +		uint8_t crc[4];
 +		if (file->size == 0)
 +			break;
 +		archive_le32enc(crc, file->crc32);
 +		r = compress_out(a, crc, 4, ARCHIVE_Z_RUN);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* Write End. */
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 +    uint64_t unpack_size, int num_coder, struct coder *coders, int substrm,
 +    uint32_t header_crc)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +	uint8_t codec_buff[8];
 +	int numFolders, fi;
 +	int codec_size;
 +	int i, r;
 +
 +	if (coders->codec == _7Z_COPY)
 +		numFolders = zip->total_number_nonempty_entry;
 +	else
 +		numFolders = 1;
 +
 +	/*
 +	 * Make PackInfo.
 +	 */
 +	r = enc_uint64(a, kPackInfo);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write PackPos. */
 +	r = enc_uint64(a, offset);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write NumPackStreams. */
 +	r = enc_uint64(a, numFolders);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Make Size. */
 +	r = enc_uint64(a, kSize);
 +	if (r < 0)
 +		return (r);
 +
 +	if (numFolders > 1) {
 +		struct file *file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->size == 0)
 +				break;
 +			r = enc_uint64(a, file->size);
 +			if (r < 0)
 +				return (r);
 +		}
 +	} else {
 +		/* Write size. */
 +		r = enc_uint64(a, pack_size);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +
 +	/*
 +	 * Make UnPackInfo.
 +	 */
 +	r = enc_uint64(a, kUnPackInfo);
 +	if (r < 0)
 +		return (r);
 +
 +	/*
 +	 * Make Folder.
 +	 */
 +	r = enc_uint64(a, kFolder);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write NumFolders. */
 +	r = enc_uint64(a, numFolders);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write External. */
 +	r = enc_uint64(a, 0);
 +	if (r < 0)
 +		return (r);
 +
 +	for (fi = 0; fi < numFolders; fi++) {
 +		/* Write NumCoders. */
 +		r = enc_uint64(a, num_coder);
 +		if (r < 0)
 +			return (r);
 +
 +		for (i = 0; i < num_coder; i++) {
 +			unsigned codec_id = coders[i].codec;
 +
 +			/* Write Codec flag. */
 +			archive_be64enc(codec_buff, codec_id);
 +			for (codec_size = 8; codec_size > 0; codec_size--) {
 +				if (codec_buff[8 - codec_size])
 +					break;
 +			}
 +			if (codec_size == 0)
 +				codec_size = 1;
 +			if (coders[i].prop_size)
 +				r = enc_uint64(a, codec_size | 0x20);
 +			else
 +				r = enc_uint64(a, codec_size);
 +			if (r < 0)
 +				return (r);
 +
 +			/* Write Codec ID. */
 +			codec_size &= 0x0f;
 +			r = compress_out(a, &codec_buff[8-codec_size],
 +				codec_size, ARCHIVE_Z_RUN);
 +			if (r < 0)
 +				return (r);
 +
 +			if (coders[i].prop_size) {
 +				/* Write Codec property size. */
 +				r = enc_uint64(a, coders[i].prop_size);
 +				if (r < 0)
 +					return (r);
 +
 +				/* Write Codec properties. */
 +				r = compress_out(a, coders[i].props,
 +					coders[i].prop_size, ARCHIVE_Z_RUN);
 +				if (r < 0)
 +					return (r);
 +			}
 +		}
 +	}
 +
 +	/*
 +	 * Make CodersUnPackSize.
 +	 */
 +	r = enc_uint64(a, kCodersUnPackSize);
 +	if (r < 0)
 +		return (r);
 +
 +	if (numFolders > 1) {
 +		struct file *file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->size == 0)
 +				break;
 +			r = enc_uint64(a, file->size);
 +			if (r < 0)
 +				return (r);
 +		}
 +
 +	} else {
 +		/* Write UnPackSize. */
 +		r = enc_uint64(a, unpack_size);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	if (!substrm) {
 +		uint8_t crc[4];
 +		/*
 +		 * Make CRC.
 +		 */
 +		r = enc_uint64(a, kCRC);
 +		if (r < 0)
 +			return (r);
 +
 +		/* All are defined */
 +		r = enc_uint64(a, 1);
 +		if (r < 0)
 +			return (r);
 +		archive_le32enc(crc, header_crc);
 +		r = compress_out(a, crc, 4, ARCHIVE_Z_RUN);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* Write End. */
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +
 +	if (substrm) {
 +		/*
 +		 * Make SubStreamsInfo.
 +		 */
 +		r = make_substreamsInfo(a, coders);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +
 +	/* Write End. */
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +
 +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 +static uint64_t
 +utcToFiletime(time_t time, long ns)
 +{
 +	uint64_t fileTime;
 +
 +	fileTime = time;
 +	fileTime *= 10000000;
 +	fileTime += ns / 100;
 +	fileTime += EPOC_TIME;
 +	return (fileTime);
 +}
 +
 +static int
 +make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)
 +{
 +	uint8_t filetime[8];
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +	struct file *file;
 +	int r;
 +	uint8_t mask, byte;
 +
 +	/*
 +	 * Make Time Bools.
 +	 */
 +	if (zip->total_number_time_defined[ti] == zip->total_number_entry) {
 +		/* Write Time Type. */
 +		r = enc_uint64(a, type);
 +		if (r < 0)
 +			return (r);
 +		/* Write EmptyStream Size. */
 +		r = enc_uint64(a, 2 + zip->total_number_entry * 8);
 +		if (r < 0)
 +			return (r);
 +		/* All are defined. */
 +		r = enc_uint64(a, 1);
 +		if (r < 0)
 +			return (r);
 +	} else {
 +		if (zip->total_number_time_defined[ti] == 0)
 +			return (ARCHIVE_OK);
 +
 +		/* Write Time Type. */
 +		r = enc_uint64(a, type);
 +		if (r < 0)
 +			return (r);
 +		/* Write EmptyStream Size. */
 +		r = enc_uint64(a, 2 + ((zip->total_number_entry + 7) >> 3)
 +			+ zip->total_number_time_defined[ti] * 8);
 +		if (r < 0)
 +			return (r);
 +
 +		/* All are not defined. */
 +		r = enc_uint64(a, 0);
 +		if (r < 0)
 +			return (r);
 +
 +		byte = 0;
 +		mask = 0x80;
 +		file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->flg & flg)
 +				byte |= mask;
 +			mask >>= 1;
 +			if (mask == 0) {
 +				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
 +				if (r < 0)
 +					return (r);
 +				mask = 0x80;
 +				byte = 0;
 +			}
 +		}
 +		if (mask != 0x80) {
 +			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
 +			if (r < 0)
 +				return (r);
 +		}
 +	}
 +
 +	/* External. */
 +	r = enc_uint64(a, 0);
 +	if (r < 0)
 +		return (r);
 +
 +
 +	/*
 +	 * Make Times.
 +	 */
 +	file = zip->file_list.first;
 +	for (;file != NULL; file = file->next) {
 +		if ((file->flg & flg) == 0)
 +			continue;
 +		archive_le64enc(filetime, utcToFiletime(file->times[ti].time,
 +			file->times[ti].time_ns));
 +		r = compress_out(a, filetime, 8, ARCHIVE_Z_RUN);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 +    uint64_t unpack_size, int codernum, struct coder *coders)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +	struct file *file;
 +	int r;
 +	uint8_t mask, byte;
 +
 +	/*
 +	 * Make FilesInfo.
 +	 */
 +	r = enc_uint64(a, kHeader);
 +	if (r < 0)
 +		return (r);
 +
 +	/*
 +	 * If there are empty files only, do not write MainStreamInfo.
 +	 */
 +	if (zip->total_number_nonempty_entry) {
 +		/*
 +		 * Make MainStreamInfo.
 +		 */
 +		r = enc_uint64(a, kMainStreamsInfo);
 +		if (r < 0)
 +			return (r);
 +		r = make_streamsInfo(a, offset, pack_size, unpack_size,
 +		      codernum, coders, 1, 0);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/*
 +	 * Make FilesInfo.
 +	 */
 +	r = enc_uint64(a, kFilesInfo);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write numFiles. */
 +	r = enc_uint64(a, zip->total_number_entry);
 +	if (r < 0)
 +		return (r);
 +
 +	if (zip->total_number_empty_entry > 0) {
 +		/* Make EmptyStream. */
 +		r = enc_uint64(a, kEmptyStream);
 +		if (r < 0)
 +			return (r);
 +
 +		/* Write EmptyStream Size. */
 +		r = enc_uint64(a, (zip->total_number_entry+7)>>3);
 +		if (r < 0)
 +			return (r);
 +
 +		byte = 0;
 +		mask = 0x80;
 +		file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->size == 0)
 +				byte |= mask;
 +			mask >>= 1;
 +			if (mask == 0) {
 +				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
 +				if (r < 0)
 +					return (r);
 +				mask = 0x80;
 +				byte = 0;
 +			}
 +		}
 +		if (mask != 0x80) {
 +			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
 +			if (r < 0)
 +				return (r);
 +		}
 +	}
 +
 +	if (zip->total_number_empty_entry > zip->total_number_dir_entry) {
 +		/* Make EmptyFile. */
 +		r = enc_uint64(a, kEmptyFile);
 +		if (r < 0)
 +			return (r);
 +
 +		/* Write EmptyFile Size. */
 +		r = enc_uint64(a, (zip->total_number_empty_entry + 7) >> 3);
 +		if (r < 0)
 +			return (r);
 +
 +		byte = 0;
 +		mask = 0x80;
 +		file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->size)
 +				continue;
 +			if (!file->dir)
 +				byte |= mask;
 +			mask >>= 1;
 +			if (mask == 0) {
 +				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
 +				if (r < 0)
 +					return (r);
 +				mask = 0x80;
 +				byte = 0;
 +			}
 +		}
 +		if (mask != 0x80) {
 +			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
 +			if (r < 0)
 +				return (r);
 +		}
 +	}
 +
 +	/* Make Name. */
 +	r = enc_uint64(a, kName);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write Nume size. */
 +	r = enc_uint64(a, zip->total_bytes_entry_name+1);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write dmy byte. */
 +	r = enc_uint64(a, 0);
 +	if (r < 0)
 +		return (r);
 +
 +	file = zip->file_list.first;
 +	for (;file != NULL; file = file->next) {
 +		r = compress_out(a, file->utf16name, file->name_len+2,
 +			ARCHIVE_Z_RUN);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* Make MTime. */
 +	r = make_time(a, kMTime, MTIME_IS_SET, MTIME);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Make CTime. */
 +	r = make_time(a, kCTime, CTIME_IS_SET, CTIME);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Make ATime. */
 +	r = make_time(a, kATime, ATIME_IS_SET, ATIME);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Make Attributes. */
 +	r = enc_uint64(a, kAttributes);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write Attributes size. */
 +	r = enc_uint64(a, 2 + zip->total_number_entry * 4);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write "All Are Defined". */
 +	r = enc_uint64(a, 1);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write dmy byte. */
 +	r = enc_uint64(a, 0);
 +	if (r < 0)
 +		return (r);
 +
 +	file = zip->file_list.first;
 +	for (;file != NULL; file = file->next) {
 +		/*
 +		 * High 16bits is unix mode.
 +		 * Low 16bits is Windows attributes.
 +		 */
 +		uint32_t encattr, attr;
 +		if (file->dir)
 +			attr = 0x8010;
 +		else
 +			attr = 0x8020;
 +		if ((file->mode & 0222) == 0)
 +			attr |= 1;/* Read Only. */
 +		attr |= ((uint32_t)file->mode) << 16;
 +		archive_le32enc(&encattr, attr);
 +		r = compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* Write End. */
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write End. */
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +
 +static int
 +_7z_free(struct archive_write *a)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +
 +	file_free_register(zip);
 +	compression_end(&(a->archive), &(zip->stream));
 +	free(zip->coder.props);
 +	free(zip);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +file_cmp_node(const struct archive_rb_node *n1,
 +    const struct archive_rb_node *n2)
 +{
 +	struct file *f1 = (struct file *)n1;
 +	struct file *f2 = (struct file *)n2;
 +
 +	if (f1->name_len == f2->name_len)
 +		return (memcmp(f1->utf16name, f2->utf16name, f1->name_len));
 +	return (f1->name_len > f2->name_len)?1:-1;
 +}
 +        
 +static int
 +file_cmp_key(const struct archive_rb_node *n, const void *key)
 +{
 +	struct file *f = (struct file *)n;
 +
 +	return (f->name_len - *(const char *)key);
 +}
 +
 +static int
 +file_new(struct archive_write *a, struct archive_entry *entry,
 +    struct file **newfile)
 +{
 +	struct _7zip *zip;
 +	struct file *file;
 +	const char *u16;
 +	size_t u16len;
 +	int ret = ARCHIVE_OK;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	*newfile = NULL;
 +
 +	file = calloc(1, sizeof(*file));
 +	if (file == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	if (0 > archive_entry_pathname_l(entry, &u16, &u16len, zip->sconv)) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for UTF-16LE");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "A filename cannot be converted to UTF-16LE;"
 +		    "You should disable making Joliet extension");
 +		ret = ARCHIVE_WARN;
 +	}
 +	file->utf16name = malloc(u16len + 2);
 +	if (file->utf16name == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory for Name");
 +		return (ARCHIVE_FATAL);
 +	}
 +	memcpy(file->utf16name, u16, u16len);
 +	file->utf16name[u16len+0] = 0;
 +	file->utf16name[u16len+1] = 0;
 +	file->name_len = u16len;
 +	file->mode = archive_entry_mode(entry);
 +	if (archive_entry_filetype(entry) == AE_IFREG)
 +		file->size = archive_entry_size(entry);
 +	else
 +		archive_entry_set_size(entry, 0);
 +	if (archive_entry_filetype(entry) == AE_IFDIR)
 +		file->dir = 1;
 +	else if (archive_entry_filetype(entry) == AE_IFLNK)
 +		file->size = strlen(archive_entry_symlink(entry));
 +	if (archive_entry_mtime_is_set(entry)) {
 +		file->flg |= MTIME_IS_SET;
 +		file->times[MTIME].time = archive_entry_mtime(entry);
 +		file->times[MTIME].time_ns = archive_entry_mtime_nsec(entry);
 +	}
 +	if (archive_entry_atime_is_set(entry)) {
 +		file->flg |= ATIME_IS_SET;
 +		file->times[ATIME].time = archive_entry_atime(entry);
 +		file->times[ATIME].time_ns = archive_entry_atime_nsec(entry);
 +	}
 +	if (archive_entry_ctime_is_set(entry)) {
 +		file->flg |= CTIME_IS_SET;
 +		file->times[CTIME].time = archive_entry_ctime(entry);
 +		file->times[CTIME].time_ns = archive_entry_ctime_nsec(entry);
 +	}
 +
 +	*newfile = file;
 +	return (ret);
 +}
 +
 +static void
 +file_free(struct file *file)
 +{
 +	free(file->utf16name);
 +	free(file);
 +}
 +
 +static void
 +file_register(struct _7zip *zip, struct file *file)
 +{
 +	file->next = NULL;
 +	*zip->file_list.last = file;
 +	zip->file_list.last = &(file->next);
 +}
 +
 +static void
 +file_init_register(struct _7zip *zip)
 +{
 +	zip->file_list.first = NULL;
 +	zip->file_list.last = &(zip->file_list.first);
 +}
 +
 +static void
 +file_free_register(struct _7zip *zip)
 +{
 +	struct file *file, *file_next;
 +
 +	file = zip->file_list.first;
 +	while (file != NULL) {
 +		file_next = file->next;
 +		file_free(file);
 +		file = file_next;
 +	}
 +}
 +
 +static void
 +file_register_empty(struct _7zip *zip, struct file *file)
 +{
 +	file->next = NULL;
 +	*zip->empty_list.last = file;
 +	zip->empty_list.last = &(file->next);
 +}
 +
 +static void
 +file_init_register_empty(struct _7zip *zip)
 +{
 +	zip->empty_list.first = NULL;
 +	zip->empty_list.last = &(zip->empty_list.first);
 +}
 +
 +#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
 +static int
 +compression_unsupported_encoder(struct archive *a,
 +    struct la_zstream *lastrm, const char *name)
 +{
 +
 +	archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +	    "%s compression not supported on this platform", name);
 +	lastrm->valid = 0;
 +	lastrm->real_stream = NULL;
 +	return (ARCHIVE_FAILED);
 +}
 +#endif
 +
++/*
++ * _7_COPY compressor.
++ */
 +static int
 +compression_init_encoder_copy(struct archive *a, struct la_zstream *lastrm)
 +{
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_copy;
 +	lastrm->end = compression_end_copy;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_copy(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	size_t bytes;
 +
 +	(void)a; /* UNUSED */
 +	if (lastrm->avail_out > lastrm->avail_in)
 +		bytes = lastrm->avail_in;
 +	else
 +		bytes = lastrm->avail_out;
 +	if (bytes) {
 +		memcpy(lastrm->next_out, lastrm->next_in, bytes);
 +		lastrm->next_in += bytes;
 +		lastrm->avail_in -= bytes;
 +		lastrm->total_in += bytes;
 +		lastrm->next_out += bytes;
 +		lastrm->avail_out -= bytes;
 +		lastrm->total_out += bytes;
 +	}
 +	if (action == ARCHIVE_Z_FINISH && lastrm->avail_in == 0)
 +		return (ARCHIVE_EOF);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_end_copy(struct archive *a, struct la_zstream *lastrm)
 +{
 +	(void)a; /* UNUSED */
 +	lastrm->valid = 0;
 +	return (ARCHIVE_OK);
 +}
 +
++/*
++ * _7_DEFLATE compressor.
++ */
 +#ifdef HAVE_ZLIB_H
 +static int
 +compression_init_encoder_deflate(struct archive *a,
 +    struct la_zstream *lastrm, int level, int withheader)
 +{
 +	z_stream *strm;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for gzip stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	/* zlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in = lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out = lastrm->total_out;
 +	if (deflateInit2(strm, level, Z_DEFLATED,
 +	    (withheader)?15:-15,
 +	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lastrm->real_stream = strm;
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_deflate;
 +	lastrm->end = compression_end_deflate;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_deflate(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	z_stream *strm;
 +	int r;
 +
 +	strm = (z_stream *)lastrm->real_stream;
 +	/* zlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in = lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out = lastrm->total_out;
 +	r = deflate(strm,
 +	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
 +	lastrm->next_in = strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in = strm->total_in;
 +	lastrm->next_out = strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out = strm->total_out;
 +	switch (r) {
 +	case Z_OK:
 +		return (ARCHIVE_OK);
 +	case Z_STREAM_END:
 +		return (ARCHIVE_EOF);
 +	default:
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "GZip compression failed:"
 +		    " deflate() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_deflate(struct archive *a, struct la_zstream *lastrm)
 +{
 +	z_stream *strm;
 +	int r;
 +
 +	strm = (z_stream *)lastrm->real_stream;
 +	r = deflateEnd(strm);
 +	free(strm);
 +	lastrm->real_stream = NULL;
 +	lastrm->valid = 0;
 +	if (r != Z_OK) {
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up compressor");
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +#else
 +static int
 +compression_init_encoder_deflate(struct archive *a,
 +    struct la_zstream *lastrm, int level, int withheader)
 +{
 +
 +	(void) level; /* UNUSED */
 +	(void) withheader; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "deflate"));
 +}
 +#endif
 +
++/*
++ * _7_BZIP2 compressor.
++ */
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +static int
 +compression_init_encoder_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	bz_stream *strm;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for bzip2 stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	/* bzlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
 +	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
 +	strm->next_out = (char *)lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
 +	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
 +	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lastrm->real_stream = strm;
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_bzip2;
 +	lastrm->end = compression_end_bzip2;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	bz_stream *strm;
 +	int r;
 +
 +	strm = (bz_stream *)lastrm->real_stream;
 +	/* bzlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
 +	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
 +	strm->next_out = (char *)lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
 +	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
 +	r = BZ2_bzCompress(strm,
 +	    (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
 +	lastrm->next_in = (const unsigned char *)strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in =
 +	    (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
 +	    + (uint64_t)(uint32_t)strm->total_in_lo32;
 +	lastrm->next_out = (unsigned char *)strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out =
 +	    (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
 +	    + (uint64_t)(uint32_t)strm->total_out_lo32;
 +	switch (r) {
 +	case BZ_RUN_OK:     /* Non-finishing */
 +	case BZ_FINISH_OK:  /* Finishing: There's more work to do */
 +		return (ARCHIVE_OK);
 +	case BZ_STREAM_END: /* Finishing: all done */
 +		/* Only occurs in finishing case */
 +		return (ARCHIVE_EOF);
 +	default:
 +		/* Any other return value indicates an error */
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Bzip2 compression failed:"
 +		    " BZ2_bzCompress() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
 +{
 +	bz_stream *strm;
 +	int r;
 +
 +	strm = (bz_stream *)lastrm->real_stream;
 +	r = BZ2_bzCompressEnd(strm);
 +	free(strm);
 +	lastrm->real_stream = NULL;
 +	lastrm->valid = 0;
 +	if (r != BZ_OK) {
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up compressor");
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +#else
 +static int
 +compression_init_encoder_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "bzip2"));
 +}
 +#endif
 +
++/*
++ * _7_LZMA1, _7_LZMA2 compressor.
++ */
 +#if defined(HAVE_LZMA_H)
 +static int
 +compression_init_encoder_lzma(struct archive *a,
 +    struct la_zstream *lastrm, int level, uint64_t filter_id)
 +{
 +	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
 +	lzma_stream *strm;
 +	lzma_filter *lzmafilters;
 +	lzma_options_lzma lzma_opt;
 +	int r;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for lzma stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lzmafilters = (lzma_filter *)(strm+1);
 +	if (level > 6)
 +		level = 6;
 +	if (lzma_lzma_preset(&lzma_opt, level)) {
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lzmafilters[0].id = filter_id;
 +	lzmafilters[0].options = &lzma_opt;
 +	lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
 +
 +	r = lzma_properties_size(&(lastrm->prop_size), lzmafilters);
 +	if (r != LZMA_OK) {
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "lzma_properties_size failed");
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (lastrm->prop_size) {
 +		lastrm->props = malloc(lastrm->prop_size);
 +		if (lastrm->props == NULL) {
 +			free(strm);
 +			lastrm->real_stream = NULL;
 +			archive_set_error(a, ENOMEM,
 +			    "Cannot allocate memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = lzma_properties_encode(lzmafilters,  lastrm->props);
 +		if (r != LZMA_OK) {
 +			free(strm);
 +			lastrm->real_stream = NULL;
 +			archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +			    "lzma_properties_encode failed");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	*strm = lzma_init_data;
 +	r = lzma_raw_encoder(strm, lzmafilters);
 +	switch (r) {
 +	case LZMA_OK:
 +		lastrm->real_stream = strm;
 +		lastrm->valid = 1;
 +		lastrm->code = compression_code_lzma;
 +		lastrm->end = compression_end_lzma;
 +		r = ARCHIVE_OK;
 +		break;
 +	case LZMA_MEM_ERROR:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library: "
 +		    "Cannot allocate memory");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +        default:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library: "
 +		    "It's a bug in liblzma");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +	}
 +	return (r);
 +}
 +
 +static int
 +compression_init_encoder_lzma1(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	return compression_init_encoder_lzma(a, lastrm, level,
 +		    LZMA_FILTER_LZMA1);
 +}
 +
 +static int
 +compression_init_encoder_lzma2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	return compression_init_encoder_lzma(a, lastrm, level,
 +		    LZMA_FILTER_LZMA2);
 +}
 +
 +static int
 +compression_code_lzma(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	lzma_stream *strm;
 +	int r;
 +
 +	strm = (lzma_stream *)lastrm->real_stream;
 +	strm->next_in = lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in = lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out = lastrm->total_out;
 +	r = lzma_code(strm,
 +	    (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
 +	lastrm->next_in = strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in = strm->total_in;
 +	lastrm->next_out = strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out = strm->total_out;
 +	switch (r) {
 +	case LZMA_OK:
 +		/* Non-finishing case */
 +		return (ARCHIVE_OK);
 +	case LZMA_STREAM_END:
 +		/* This return can only occur in finishing case. */
 +		return (ARCHIVE_EOF);
 +	case LZMA_MEMLIMIT_ERROR:
 +		archive_set_error(a, ENOMEM,
 +		    "lzma compression error:"
 +		    " %ju MiB would have been needed",
 +		    (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
 +			/ (1024 * 1024)));
 +		return (ARCHIVE_FATAL);
 +	default:
 +		/* Any other return value indicates an error */
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "lzma compression failed:"
 +		    " lzma_code() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_lzma(struct archive *a, struct la_zstream *lastrm)
 +{
 +	lzma_stream *strm;
 +
 +	(void)a; /* UNUSED */
 +	strm = (lzma_stream *)lastrm->real_stream;
 +	lzma_end(strm);
 +	free(strm);
 +	lastrm->valid = 0;
 +	lastrm->real_stream = NULL;
 +	return (ARCHIVE_OK);
 +}
 +#else
 +static int
 +compression_init_encoder_lzma1(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "lzma"));
 +}
 +static int
 +compression_init_encoder_lzma2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "lzma"));
 +}
 +#endif
 +
 +/*
-  * PPMd compression.
++ * _7_PPMD compressor.
 + */
 +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 void
 +ppmd_write(void *p, Byte b)
 +{
 +	struct archive_write *a = ((IByteOut *)p)->a;
 +	struct _7zip *zip = (struct _7zip *)(a->format_data);
 +	struct la_zstream *lastrm = &(zip->stream);
 +	struct ppmd_stream *strm;
 +
 +	if (lastrm->avail_out) {
 +		*lastrm->next_out++ = b;
 +		lastrm->avail_out--;
 +		lastrm->total_out++;
 +		return;
 +	}
 +	strm = (struct ppmd_stream *)lastrm->real_stream;
 +	if (strm->buff_ptr < strm->buff_end) {
 +		*strm->buff_ptr++ = b;
 +		strm->buff_bytes++;
 +	}
 +}
 +
 +static int
 +compression_init_encoder_ppmd(struct archive *a,
 +    struct la_zstream *lastrm, unsigned maxOrder, uint32_t msize)
 +{
 +	struct ppmd_stream *strm;
 +	uint8_t *props;
 +	int r;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for PPMd");
 +		return (ARCHIVE_FATAL);
 +	}
 +	strm->buff = malloc(32);
 +	if (strm->buff == NULL) {
 +		free(strm);
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for PPMd");
 +		return (ARCHIVE_FATAL);
 +	}
 +	strm->buff_ptr = strm->buff;
 +	strm->buff_end = strm->buff + 32;
 +
 +	props = malloc(1+4);
 +	if (props == NULL) {
 +		free(strm->buff);
 +		free(strm);
 +		archive_set_error(a, ENOMEM,
 +		    "Coludn't allocate memory for PPMd");
 +		return (ARCHIVE_FATAL);
 +	}
 +	props[0] = maxOrder;
 +	archive_le32enc(props+1, msize);
 +	__archive_ppmd7_functions.Ppmd7_Construct(&strm->ppmd7_context);
 +	r = __archive_ppmd7_functions.Ppmd7_Alloc(
 +		&strm->ppmd7_context, msize, &g_szalloc);
 +	if (r == 0) {
 +		free(strm->buff);
 +		free(strm);
 +		free(props);
 +		archive_set_error(a, ENOMEM,
 +		    "Coludn't allocate memory for PPMd");
 +		return (ARCHIVE_FATAL);
 +	}
 +	__archive_ppmd7_functions.Ppmd7_Init(&(strm->ppmd7_context), maxOrder);
 +	strm->byteout.a = (struct archive_write *)a;
 +	strm->byteout.Write = ppmd_write;
 +	strm->range_enc.Stream = &(strm->byteout);
 +	__archive_ppmd7_functions.Ppmd7z_RangeEnc_Init(&(strm->range_enc));
 +	strm->stat = 0;
 +
 +	lastrm->real_stream = strm;
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_ppmd;
 +	lastrm->end = compression_end_ppmd;
 +	lastrm->prop_size = 5;
 +	lastrm->props = props;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_ppmd(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	struct ppmd_stream *strm;
 +
 +	strm = (struct ppmd_stream *)lastrm->real_stream;
 +
 +	/* Copy encoded data if there are remaining bytes from previous call. */
 +	if (strm->buff_bytes) {
 +		uint8_t *p = strm->buff_ptr - strm->buff_bytes;
 +		while (lastrm->avail_out && strm->buff_bytes) {
 +			*lastrm->next_out++ = *p++;
 +			lastrm->avail_out--;
 +			lastrm->total_out++;
 +			strm->buff_bytes--;
 +		}
 +		if (strm->buff_bytes)
 +			return (ARCHIVE_OK);
 +		if (strm->stat == 1)
 +			return (ARCHIVE_EOF);
 +		strm->buff_ptr = strm->buff;
 +	}
 +	while (lastrm->avail_in && lastrm->avail_out) {
 +		__archive_ppmd7_functions.Ppmd7_EncodeSymbol(
 +			&(strm->ppmd7_context), &(strm->range_enc),
 +			*lastrm->next_in++);
 +		lastrm->avail_in--;
 +		lastrm->total_in++;
 +	}
 +	if (lastrm->avail_in == 0 && action == ARCHIVE_Z_FINISH) {
 +		__archive_ppmd7_functions.Ppmd7z_RangeEnc_FlushData(
 +			&(strm->range_enc));
 +		strm->stat = 1;
 +		/* Return EOF if there are no remaining bytes. */
 +		if (strm->buff_bytes == 0)
 +			return (ARCHIVE_EOF);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_end_ppmd(struct archive *a, struct la_zstream *lastrm)
 +{
 +	struct ppmd_stream *strm;
 +
 +	strm = (struct ppmd_stream *)lastrm->real_stream;
 +	__archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context, &g_szalloc);
 +	free(strm->buff);
 +	free(strm);
 +	lastrm->real_stream = NULL;
 +	lastrm->valid = 0;
 +	return (ARCHIVE_OK);
 +}
 +
++/*
++ * Universal compressor initializer.
++ */
 +static int
 +_7z_compression_init_encoder(struct archive_write *a, unsigned compression,
 +    int compression_level)
 +{
 +	struct _7zip *zip;
 +	int r;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	switch (compression) {
 +	case _7Z_DEFLATE:
 +		r = compression_init_encoder_deflate(
 +		    &(a->archive), &(zip->stream),
 +		    compression_level, 0);
 +		break;
 +	case _7Z_BZIP2:
 +		r = compression_init_encoder_bzip2(
 +		    &(a->archive), &(zip->stream),
 +		    compression_level);
 +		break;
 +	case _7Z_LZMA1:
 +		r = compression_init_encoder_lzma1(
 +		    &(a->archive), &(zip->stream),
 +		    compression_level);
 +		break;
 +	case _7Z_LZMA2:
 +		r = compression_init_encoder_lzma2(
 +		    &(a->archive), &(zip->stream),
 +		    compression_level);
 +		break;
 +	case _7Z_PPMD:
 +		r = compression_init_encoder_ppmd(
 +		    &(a->archive), &(zip->stream),
 +		    PPMD7_DEFAULT_ORDER, PPMD7_DEFAULT_MEM_SIZE);
 +		break;
 +	case _7Z_COPY:
 +	default:
 +		r = compression_init_encoder_copy(
 +		    &(a->archive), &(zip->stream));
 +		break;
 +	}
 +	if (r == ARCHIVE_OK) {
 +		zip->stream.total_in = 0;
 +		zip->stream.next_out = zip->wbuff;
 +		zip->stream.avail_out = sizeof(zip->wbuff);
 +		zip->stream.total_out = 0;
 +	}
 +
 +	return (r);
 +}
 +
 +static int
 +compression_code(struct archive *a, struct la_zstream *lastrm,
 +    enum la_zaction action)
 +{
 +	if (lastrm->valid)
 +		return (lastrm->code(a, lastrm, action));
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_end(struct archive *a, struct la_zstream *lastrm)
 +{
 +	if (lastrm->valid) {
 +		lastrm->prop_size = 0;
 +		free(lastrm->props);
 +		lastrm->props = NULL;
 +		return (lastrm->end(a, lastrm));
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +
diff --cc Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c
index 6b8741f,0000000..0f003a8
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c
@@@ -1,3168 -1,0 +1,3171 @@@
 +/*-
 + * 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$");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_LIMITS_H
 +#include <limits.h>
 +#endif
 +#include <stdlib.h>
 +#if HAVE_LIBXML_XMLWRITER_H
 +#include <libxml/xmlwriter.h>
 +#endif
 +#ifdef HAVE_BZLIB_H
 +#include <bzlib.h>
 +#endif
 +#if HAVE_LZMA_H
 +#include <lzma.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_crypto_private.h"
 +#include "archive_endian.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_private.h"
 +#include "archive_rb.h"
 +#include "archive_string.h"
 +#include "archive_write_private.h"
 +
 +/*
 + * Differences to xar utility.
 + * - Subdocument is not supported yet.
 + * - ACL is not supported yet.
 + * - When writing an XML element <link type="<file-type>">, <file-type>
 + *   which is a file type a symbolic link is referencing is always marked
 + *   as "broken". Xar utility uses stat(2) to get the file type, but, in
 + *   libarcive format writer, we should not use it; if it is needed, we
 + *   should get about it at archive_read_disk.c.
 + * - It is possible to appear both <flags> and <ext2> elements.
 + *   Xar utility generates <flags> on BSD platform and <ext2> on Linux
 + *   platform.
 + *
 + */
 +
 +#if !(defined(HAVE_LIBXML_XMLWRITER_H) && defined(LIBXML_VERSION) &&\
 +	LIBXML_VERSION >= 20703) ||\
 +	!defined(HAVE_ZLIB_H) || \
 +	!defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
 +/*
 + * xar needs several external libraries.
 + *   o libxml2
 + *   o openssl or MD5/SHA1 hash function
 + *   o zlib
 + *   o bzlib2 (option)
 + *   o liblzma (option)
 + */
 +int
 +archive_write_set_format_xar(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +	    "Xar not supported on this platform");
 +	return (ARCHIVE_WARN);
 +}
 +
 +#else	/* Support xar format */
 +
 +/*#define DEBUG_PRINT_TOC		1 */
 +
 +#define HEADER_MAGIC	0x78617221
 +#define HEADER_SIZE	28
 +#define HEADER_VERSION	1
 +
 +enum sumalg {
 +	CKSUM_NONE = 0,
 +	CKSUM_SHA1 = 1,
 +	CKSUM_MD5 = 2
 +};
 +
 +#define MD5_SIZE	16
 +#define SHA1_SIZE	20
 +#define MAX_SUM_SIZE	20
 +#define MD5_NAME	"md5"
 +#define SHA1_NAME	"sha1"
 + 
 +enum enctype {
 +	NONE,
 +	GZIP,
 +	BZIP2,
 +	LZMA,
 +	XZ,
 +};
 +
 +struct chksumwork {
 +	enum sumalg		 alg;
 +#ifdef ARCHIVE_HAS_MD5
 +	archive_md5_ctx		 md5ctx;
 +#endif
 +#ifdef ARCHIVE_HAS_SHA1
 +	archive_sha1_ctx	 sha1ctx;
 +#endif
 +};
 +
 +enum la_zaction {
 +	ARCHIVE_Z_FINISH,
 +	ARCHIVE_Z_RUN
 +};
 +
 +/*
 + * Universal zstream.
 + */
 +struct la_zstream {
 +	const unsigned char	*next_in;
 +	size_t			 avail_in;
 +	uint64_t		 total_in;
 +
 +	unsigned char		*next_out;
 +	size_t			 avail_out;
 +	uint64_t		 total_out;
 +
 +	int			 valid;
 +	void			*real_stream;
 +	int			 (*code) (struct archive *a,
 +				    struct la_zstream *lastrm,
 +				    enum la_zaction action);
 +	int			 (*end)(struct archive *a,
 +				    struct la_zstream *lastrm);
 +};
 +
 +struct chksumval {
 +	enum sumalg		 alg;
 +	size_t			 len;
 +	unsigned char		 val[MAX_SUM_SIZE];
 +};
 +
 +struct heap_data {
 +	int			 id;
 +	struct heap_data	*next;
 +	uint64_t		 temp_offset;
 +	uint64_t		 length;	/* archived size.	*/
 +	uint64_t		 size;		/* extracted size.	*/
 +	enum enctype		 compression;
 +	struct chksumval	 a_sum;		/* archived checksum.	*/
 +	struct chksumval	 e_sum;		/* extracted checksum.	*/
 +};
 +
 +struct file {
 +	struct archive_rb_node	 rbnode;
 +
 +	int			 id;
 +	struct archive_entry	*entry;
 +
 +	struct archive_rb_tree	 rbtree;
 +	struct file		*next;
 +	struct file		*chnext;
 +	struct file		*hlnext;
 +	/* For hardlinked files.
 +	 * Use only when archive_entry_nlink() > 1 */
 +	struct file		*hardlink_target;
 +	struct file		*parent;	/* parent directory entry */
 +	/*
 +	 * To manage sub directory files.
 +	 * We use 'chnext' a menber of struct file to chain.
 +	 */
 +	struct {
 +		struct file	*first;
 +		struct file	**last;
 +	}			 children;
 +
 +	/* For making a directory tree. */
 +        struct archive_string    parentdir;
 +        struct archive_string    basename;
 +        struct archive_string    symlink;
 +
 +	int			 ea_idx;
 +	struct {
 +		struct heap_data *first;
 +		struct heap_data **last;
 +	}			 xattr;
 +	struct heap_data	 data;
 +        struct archive_string    script;
 +
 +	int			 virtual:1;
 +	int			 dir:1;
 +};
 +
 +struct hardlink {
 +	struct archive_rb_node	 rbnode;
 +	int			 nlink;
 +	struct {
 +		struct file	*first;
 +		struct file	**last;
 +	}			 file_list;
 +};
 +
 +struct xar {
 +	int			 temp_fd;
 +	uint64_t		 temp_offset;
 +
 +	int			 file_idx;
 +	struct file		*root;
 +	struct file		*cur_dirent;
 +	struct archive_string	 cur_dirstr;
 +	struct file		*cur_file;
 +	uint64_t		 bytes_remaining;
 +	struct archive_string	 tstr;
 +	struct archive_string	 vstr;
 +
 +	enum sumalg		 opt_toc_sumalg;
 +	enum sumalg		 opt_sumalg;
 +	enum enctype		 opt_compression;
 +	int			 opt_compression_level;
 +
 +	struct chksumwork	 a_sumwrk;	/* archived checksum.	*/
 +	struct chksumwork	 e_sumwrk;	/* extracted checksum.	*/
 +	struct la_zstream	 stream;
 +	struct archive_string_conv *sconv;
 +	/*
 +	 * Compressed data buffer.
 +	 */
 +	unsigned char		 wbuff[1024 * 64];
 +	size_t			 wbuff_remaining;
 +
 +	struct heap_data	 toc;
 +	/*
 +	 * The list of all file entries is used to manage struct file
 +	 * objects.
 +	 * We use 'next' a menber of struct file to chain.
 +	 */
 +	struct {
 +		struct file	*first;
 +		struct file	**last;
 +	}			 file_list;
 +	/*
 +	 * The list of hard-linked file entries.
 +	 * We use 'hlnext' a menber of struct file to chain.
 +	 */
 +	struct archive_rb_tree	 hardlink_rbtree;
 +};
 +
 +static int	xar_options(struct archive_write *,
 +		    const char *, const char *);
 +static int	xar_write_header(struct archive_write *,
 +		    struct archive_entry *);
 +static ssize_t	xar_write_data(struct archive_write *,
 +		    const void *, size_t);
 +static int	xar_finish_entry(struct archive_write *);
 +static int	xar_close(struct archive_write *);
 +static int	xar_free(struct archive_write *);
 +
 +static struct file *file_new(struct archive_write *a, struct archive_entry *);
 +static void	file_free(struct file *);
 +static struct file *file_create_virtual_dir(struct archive_write *a, struct xar *,
 +		    const char *);
 +static int	file_add_child_tail(struct file *, struct file *);
 +static struct file *file_find_child(struct file *, const char *);
 +static int	file_gen_utility_names(struct archive_write *,
 +		    struct file *);
 +static int	get_path_component(char *, int, const char *);
 +static int	file_tree(struct archive_write *, struct file **);
 +static void	file_register(struct xar *, struct file *);
 +static void	file_init_register(struct xar *);
 +static void	file_free_register(struct xar *);
 +static int	file_register_hardlink(struct archive_write *,
 +		    struct file *);
 +static void	file_connect_hardlink_files(struct xar *);
 +static void	file_init_hardlinks(struct xar *);
 +static void	file_free_hardlinks(struct xar *);
 +
 +static void	checksum_init(struct chksumwork *, enum sumalg);
 +static void	checksum_update(struct chksumwork *, const void *, size_t);
 +static void	checksum_final(struct chksumwork *, struct chksumval *);
 +static int	compression_init_encoder_gzip(struct archive *,
 +		    struct la_zstream *, int, int);
 +static int	compression_code_gzip(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_gzip(struct archive *, struct la_zstream *);
 +static int	compression_init_encoder_bzip2(struct archive *,
 +		    struct la_zstream *, int);
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +static int	compression_code_bzip2(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_bzip2(struct archive *, struct la_zstream *);
 +#endif
 +static int	compression_init_encoder_lzma(struct archive *,
 +		    struct la_zstream *, int);
 +static int	compression_init_encoder_xz(struct archive *,
 +		    struct la_zstream *, int);
 +#if defined(HAVE_LZMA_H)
 +static int	compression_code_lzma(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_lzma(struct archive *, struct la_zstream *);
 +#endif
 +static int	xar_compression_init_encoder(struct archive_write *);
 +static int	compression_code(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end(struct archive *,
 +		    struct la_zstream *);
 +static int	save_xattrs(struct archive_write *, struct file *);
 +static int	getalgsize(enum sumalg);
 +static const char *getalgname(enum sumalg);
 +
 +int
 +archive_write_set_format_xar(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct xar *xar;
 +
 +	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_write_set_format_xar");
 +
 +	/* If another format was already registered, unregister it. */
 +	if (a->format_free != NULL)
 +		(a->format_free)(a);
 +
 +	xar = calloc(1, sizeof(*xar));
 +	if (xar == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate xar data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	xar->temp_fd = -1;
 +	file_init_register(xar);
 +	file_init_hardlinks(xar);
 +	archive_string_init(&(xar->tstr));
 +	archive_string_init(&(xar->vstr));
 +
 +	/*
 +	 * Create the root directory.
 +	 */
 +	xar->root = file_create_virtual_dir(a, xar, "");
 +	if (xar->root == NULL) {
 +		free(xar);
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate xar data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	xar->root->parent = xar->root;
 +	file_register(xar, xar->root);
 +	xar->cur_dirent = xar->root;
 +	archive_string_init(&(xar->cur_dirstr));
 +	archive_string_ensure(&(xar->cur_dirstr), 1);
 +	xar->cur_dirstr.s[0] = 0;
 +
 +	/*
 +	 * Initialize option.
 +	 */
 +	/* Set default checksum type. */
 +	xar->opt_toc_sumalg = CKSUM_SHA1;
 +	xar->opt_sumalg = CKSUM_SHA1;
 +	/* Set default compression type and level. */
 +	xar->opt_compression = GZIP;
 +	xar->opt_compression_level = 6;
 +
 +	a->format_data = xar;
 +
 +	a->format_name = "xar";
 +	a->format_options = xar_options;
 +	a->format_write_header = xar_write_header;
 +	a->format_write_data = xar_write_data;
 +	a->format_finish_entry = xar_finish_entry;
 +	a->format_close = xar_close;
 +	a->format_free = xar_free;
 +	a->archive.archive_format = ARCHIVE_FORMAT_XAR;
 +	a->archive.archive_format_name = "xar";
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xar_options(struct archive_write *a, const char *key, const char *value)
 +{
 +	struct xar *xar;
 +
 +	xar = (struct xar *)a->format_data;
 +
 +	if (strcmp(key, "checksum") == 0) {
 +		if (value == NULL)
 +			xar->opt_sumalg = CKSUM_NONE;
 +		else if (strcmp(value, "sha1") == 0)
 +			xar->opt_sumalg = CKSUM_SHA1;
 +		else if (strcmp(value, "md5") == 0)
 +			xar->opt_sumalg = CKSUM_MD5;
 +		else {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Unkonwn checksum name: `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +	if (strcmp(key, "compression") == 0) {
 +		const char *name = NULL;
 +
 +		if (value == NULL)
 +			xar->opt_compression = NONE;
 +		else if (strcmp(value, "gzip") == 0)
 +			xar->opt_compression = GZIP;
 +		else if (strcmp(value, "bzip2") == 0)
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +			xar->opt_compression = BZIP2;
 +#else
 +			name = "bzip2";
 +#endif
 +		else if (strcmp(value, "lzma") == 0)
 +#if HAVE_LZMA_H
 +			xar->opt_compression = LZMA;
 +#else
 +			name = "lzma";
 +#endif
 +		else if (strcmp(value, "xz") == 0)
 +#if HAVE_LZMA_H
 +			xar->opt_compression = XZ;
 +#else
 +			name = "xz";
 +#endif
 +		else {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Unkonwn compression name: `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		if (name != NULL) {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "`%s' compression not supported "
 +			    "on this platform",
 +			    name);
 +			return (ARCHIVE_FAILED);
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +	if (strcmp(key, "compression-level") == 0) {
 +		if (value == NULL ||
 +		    !(value[0] >= '0' && value[0] <= '9') ||
 +		    value[1] != '\0') {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Illeagal value `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		xar->opt_compression_level = value[0] - '0';
 +		return (ARCHIVE_OK);
 +	}
 +	if (strcmp(key, "toc-checksum") == 0) {
 +		if (value == NULL)
 +			xar->opt_toc_sumalg = CKSUM_NONE;
 +		else if (strcmp(value, "sha1") == 0)
 +			xar->opt_toc_sumalg = CKSUM_SHA1;
 +		else if (strcmp(value, "md5") == 0)
 +			xar->opt_toc_sumalg = CKSUM_MD5;
 +		else {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Unkonwn checksum name: `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +
 +	return (ARCHIVE_FAILED);
 +}
 +
 +static int
 +xar_write_header(struct archive_write *a, struct archive_entry *entry)
 +{
 +	struct xar *xar;
 +	struct file *file;
 +	struct archive_entry *file_entry;
 +	int r, r2;
 +
 +	xar = (struct xar *)a->format_data;
 +	xar->cur_file = NULL;
 +	xar->bytes_remaining = 0;
 +
 +	if (xar->sconv == NULL) {
 +		xar->sconv = archive_string_conversion_to_charset(
 +		    &a->archive, "UTF-8", 1);
 +		if (xar->sconv == NULL)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	file = file_new(a, entry);
 +	if (file == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	r2 = file_gen_utility_names(a, file);
 +	if (r2 < ARCHIVE_WARN)
 +		return (r2);
 +
 +	/*
 +	 * Ignore a path which looks like the top of directory name
 +	 * since we have already made the root directory of an Xar archive.
 +	 */
 +	if (archive_strlen(&(file->parentdir)) == 0 &&
 +	    archive_strlen(&(file->basename)) == 0) {
 +		file_free(file);
 +		return (r2);
 +	}
 +
 +	/* Add entry into tree */
 +	file_entry = file->entry;
 +	r = file_tree(a, &file);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* There is the same file in tree and
 +	 * the current file is older than the file in tree.
 +	 * So we don't need the current file data anymore. */
 +	if (file->entry != file_entry)
 +		return (r2);
 +	if (file->id == 0)
 +		file_register(xar, file);
 +
 +	/* A virtual file, which is a directory, does not have
 +	 * any contents and we won't store it into a archive
 +	 * file other than its name. */
 +	if (file->virtual)
 +		return (r2);
 +
 +	/*
 +	 * Prepare to save the contents of the file.
 +	 */
 +	if (xar->temp_fd == -1) {
 +		int algsize;
 +		xar->temp_offset = 0;
 +		xar->temp_fd = __archive_mktemp(NULL);
 +		if (xar->temp_fd < 0) {
 +			archive_set_error(&a->archive, errno,
 +			    "Couldn't create temporary file");
 +			return (ARCHIVE_FATAL);
 +		}
 +		algsize = getalgsize(xar->opt_toc_sumalg);
 +		if (algsize > 0) {
 +			if (lseek(xar->temp_fd, algsize, SEEK_SET) < 0) {
 +				archive_set_error(&(a->archive), errno,
 +				    "lseek failed");
 +				return (ARCHIVE_FATAL);
 +			}
 +			xar->temp_offset = algsize;
 +		}
 +	}
 +
 +	if (archive_entry_hardlink(file->entry) == NULL) {
 +		r = save_xattrs(a, file);
 +		if (r != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Non regular files contents are unneeded to be saved to
 +	 * a temporary file. */
 +	if (archive_entry_filetype(file->entry) != AE_IFREG)
 +		return (r2);
 +
 +	/*
 +	 * Set the current file to cur_file to read its contents.
 +	 */
 +	xar->cur_file = file;
 +
 +	if (archive_entry_nlink(file->entry) > 1) {
 +		r = file_register_hardlink(a, file);
 +		if (r != ARCHIVE_OK)
 +			return (r);
 +		if (archive_entry_hardlink(file->entry) != NULL) {
 +			archive_entry_unset_size(file->entry);
 +			return (r2);
 +		}
 +	}
 +
 +	/* Save a offset of current file in temporary file. */
 +	file->data.temp_offset = xar->temp_offset;
 +	file->data.size = archive_entry_size(file->entry);
 +	file->data.compression = xar->opt_compression;
 +	xar->bytes_remaining = archive_entry_size(file->entry);
 +	checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
 +	checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
 +	r = xar_compression_init_encoder(a);
 +
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	else
 +		return (r2);
 +}
 +
 +static int
 +write_to_temp(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct xar *xar;
 +	unsigned char *p;
 +	ssize_t ws;
 +
 +	xar = (struct xar *)a->format_data;
 +	p = (unsigned char *)buff;
 +	while (s) {
 +		ws = write(xar->temp_fd, p, s);
 +		if (ws < 0) {
 +			archive_set_error(&(a->archive), errno,
 +			    "fwrite function failed");
 +			return (ARCHIVE_FATAL);
 +		}
 +		s -= ws;
 +		p += ws;
 +		xar->temp_offset += ws;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static ssize_t
 +xar_write_data(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct xar *xar;
 +	enum la_zaction run;
 +	size_t size, rsize;
 +	int r;
 +
 +	xar = (struct xar *)a->format_data;
 +
 +	if (s > xar->bytes_remaining)
 +		s = xar->bytes_remaining;
 +	if (s == 0 || xar->cur_file == NULL)
 +		return (0);
 +	if (xar->cur_file->data.compression == NONE) {
 +		checksum_update(&(xar->e_sumwrk), buff, s);
 +		checksum_update(&(xar->a_sumwrk), buff, s);
 +		size = rsize = s;
 +	} else {
 +		xar->stream.next_in = (const unsigned char *)buff;
 +		xar->stream.avail_in = s;
 +		if (xar->bytes_remaining > s)
 +			run = ARCHIVE_Z_RUN;
 +		else
 +			run = ARCHIVE_Z_FINISH;
 +		/* Compress file data. */
 +		r = compression_code(&(a->archive), &(xar->stream), run);
 +		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
 +			return (ARCHIVE_FATAL);
 +		rsize = s - xar->stream.avail_in;
 +		checksum_update(&(xar->e_sumwrk), buff, rsize);
 +		size = sizeof(xar->wbuff) - xar->stream.avail_out;
 +		checksum_update(&(xar->a_sumwrk), xar->wbuff, size);
 +	}
 +#if !defined(_WIN32) || defined(__CYGWIN__)
 +	if (xar->bytes_remaining ==
 +	    archive_entry_size(xar->cur_file->entry)) {
 +		/*
 +		 * Get the path of a shell script if so.
 +		 */
 +		const unsigned char *b = (const unsigned char *)buff;
 +
 +		archive_string_empty(&(xar->cur_file->script));
 +		if (rsize > 2 && b[0] == '#' && b[1] == '!') {
- 			char path[PATH_MAX];
 +			size_t i, end, off;
 +
- 			end = sizeof(path);
- 			if (end > rsize)
- 				end = rsize;
 +			off = 2;
 +			if (b[off] == ' ')
 +				off++;
++#ifdef PATH_MAX
++			if ((rsize - off) > PATH_MAX)
++				end = off + PATH_MAX;
++			else
++#endif
++				end = rsize;
++			/* Find the end of a script path. */
 +			for (i = off; i < end && b[i] != '\0' &&
 +			    b[i] != '\n' && b[i] != '\r' &&
 +			    b[i] != ' ' && b[i] != '\t'; i++)
- 				path[i - off] = b[i];
- 			path[i - off] = '\0';
- 			archive_strcpy(&(xar->cur_file->script), path);
++				;
++			archive_strncpy(&(xar->cur_file->script), b + off,
++			    i - off);
 +		}
 +	}
 +#endif
 +
 +	if (xar->cur_file->data.compression == NONE) {
 +		if (write_to_temp(a, buff, size) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	} else {
 +		if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +	xar->bytes_remaining -= rsize;
 +	xar->cur_file->data.length += size;
 +
 +	return (rsize);
 +}
 +
 +static int
 +xar_finish_entry(struct archive_write *a)
 +{
 +	struct xar *xar;
 +	struct file *file;
 +	size_t s;
 +	ssize_t w;
 +
 +	xar = (struct xar *)a->format_data;
 +	if (xar->cur_file == NULL)
 +		return (ARCHIVE_OK);
 +
 +	while (xar->bytes_remaining > 0) {
 +		s = xar->bytes_remaining;
 +		if (s > a->null_length)
 +			s = a->null_length;
 +		w = xar_write_data(a, a->nulls, s);
 +		if (w > 0)
 +			xar->bytes_remaining -= w;
 +		else
 +			return (w);
 +	}
 +	file = xar->cur_file;
 +	checksum_final(&(xar->e_sumwrk), &(file->data.e_sum));
 +	checksum_final(&(xar->a_sumwrk), &(file->data.a_sum));
 +	xar->cur_file = NULL;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, const char *value,
 +	const char *attrkey, const char *attrvalue)
 +{
 +	int r;
 +
 +	r = xmlTextWriterStartElement(writer, BAD_CAST(key));
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterStartElement() failed: %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (attrkey != NULL && attrvalue != NULL) {
 +		r = xmlTextWriterWriteAttribute(writer,
 +		    BAD_CAST(attrkey), BAD_CAST(attrvalue));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteAttribute() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +	if (value != NULL) {
 +		r = xmlTextWriterWriteString(writer, BAD_CAST(value));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteString() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +	r = xmlTextWriterEndElement(writer);
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterEndElement() failed: %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, const char *value)
 +{
 +	int r;
 +
 +	if (value == NULL)
 +		return (ARCHIVE_OK);
 +	
 +	r = xmlTextWriterStartElement(writer, BAD_CAST(key));
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterStartElement() failed: %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (value != NULL) {
 +		r = xmlTextWriterWriteString(writer, BAD_CAST(value));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteString() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +	r = xmlTextWriterEndElement(writer);
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterEndElement() failed: %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xmlwrite_fstring(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, const char *fmt, ...)
 +{
 +	struct xar *xar;
 +	va_list ap;
 +
 +	xar = (struct xar *)a->format_data;
 +	va_start(ap, fmt);
 +	archive_string_empty(&xar->vstr);
 +	archive_string_vsprintf(&xar->vstr, fmt, ap);
 +	va_end(ap);
 +	return (xmlwrite_string(a, writer, key, xar->vstr.s));
 +}
 +
 +static int
 +xmlwrite_time(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, time_t t, int z)
 +{
 +	char timestr[100];
 +	struct tm tm;
 +
 +#if defined(HAVE_GMTIME_R)
 +	gmtime_r(&t, &tm);
 +#elif defined(HAVE__GMTIME64_S)
 +	_gmtime64_s(&tm, &t);
 +#else
 +	memcpy(&tm, gmtime(&t), sizeof(tm));
 +#endif
 +	memset(&timestr, 0, sizeof(timestr));
 +	/* Do not use %F and %T for portability. */
 +	strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%S", &tm);
 +	if (z)
 +		strcat(timestr, "Z");
 +	return (xmlwrite_string(a, writer, key, timestr));
 +}
 +
 +static int
 +xmlwrite_mode(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, mode_t mode)
 +{
 +	char ms[5];
 +
 +	ms[0] = '0';
 +	ms[1] = '0' + ((mode >> 6) & 07);
 +	ms[2] = '0' + ((mode >> 3) & 07);
 +	ms[3] = '0' + (mode & 07);
 +	ms[4] = '\0';
 +
 +	return (xmlwrite_string(a, writer, key, ms));
 +}
 +
 +static int
 +xmlwrite_sum(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, struct chksumval *sum)
 +{
 +	const char *algname;
 +	int algsize;
 +	char buff[MAX_SUM_SIZE*2 + 1];
 +	char *p;
 +	unsigned char *s;
 +	int i, r;
 +
 +	if (sum->len > 0) {
 +		algname = getalgname(sum->alg);
 +		algsize = getalgsize(sum->alg);
 +		if (algname != NULL) {
 +			const char *hex = "0123456789abcdef";
 +			p = buff;
 +			s = sum->val;
 +			for (i = 0; i < algsize; i++) {
 +				*p++ = hex[(*s >> 4)];
 +				*p++ = hex[(*s & 0x0f)];
 +				s++;
 +			}
 +			*p = '\0';
 +			r = xmlwrite_string_attr(a, writer,
 +			    key, buff,
 +			    "style", algname);
 +			if (r < 0)
 +				return (ARCHIVE_FATAL);
 +		}
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xmlwrite_heap(struct archive_write *a, xmlTextWriterPtr writer,
 +	struct heap_data *heap)
 +{
 +	const char *encname;
 +	int r;
 +
 +	r = xmlwrite_fstring(a, writer, "length", "%ju", heap->length);
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = xmlwrite_fstring(a, writer, "offset", "%ju", heap->temp_offset);
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = xmlwrite_fstring(a, writer, "size", "%ju", heap->size);
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	switch (heap->compression) {
 +	case GZIP:
 +		encname = "application/x-gzip"; break;
 +	case BZIP2:
 +		encname = "application/x-bzip2"; break;
 +	case LZMA:
 +		encname = "application/x-lzma"; break;
 +	case XZ:
 +		encname = "application/x-xz"; break;
 +	default:
 +		encname = "application/octet-stream"; break;
 +	}
 +	r = xmlwrite_string_attr(a, writer, "encoding", NULL,
 +	    "style", encname);
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = xmlwrite_sum(a, writer, "archived-checksum", &(heap->a_sum));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = xmlwrite_sum(a, writer, "extracted-checksum", &(heap->e_sum));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * xar utility records fflags as following xml elements:
 + *   <flags>
 + *     <UserNoDump/>
 + *     .....
 + *   </flags>
 + * or
 + *   <ext2>
 + *     <NoDump/>
 + *     .....
 + *   </ext2>
 + * If xar is running on BSD platform, records <flags>..</flags>;
 + * if xar is running on linux platform, records <ext2>..</ext2>;
 + * otherwise does not record.
 + *
 + * Our implements records both <flags> and <ext2> if it's necessary.
 + */
 +static int
 +make_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer,
 +    const char *element, const char *fflags_text)
 +{
 +	static const struct flagentry {
 +		const char	*name;
 +		const char	*xarname;
 +	}
 +	flagbsd[] = {
 +		{ "sappnd",	"SystemAppend"},
 +		{ "sappend",	"SystemAppend"},
 +		{ "arch",	"SystemArchived"},
 +		{ "archived",	"SystemArchived"},
 +		{ "schg",	"SystemImmutable"},
 +		{ "schange",	"SystemImmutable"},
 +		{ "simmutable",	"SystemImmutable"},
 +		{ "nosunlnk",	"SystemNoUnlink"},
 +		{ "nosunlink",	"SystemNoUnlink"},
 +		{ "snapshot",	"SystemSnapshot"},
 +		{ "uappnd",	"UserAppend"},
 +		{ "uappend",	"UserAppend"},
 +		{ "uchg",	"UserImmutable"},
 +		{ "uchange",	"UserImmutable"},
 +		{ "uimmutable",	"UserImmutable"},
 +		{ "nodump",	"UserNoDump"},
 +		{ "noopaque",	"UserOpaque"},
 +		{ "nouunlnk",	"UserNoUnlink"},
 +		{ "nouunlink",	"UserNoUnlink"},
 +		{ NULL, NULL}
 +	},
 +	flagext2[] = {
 +		{ "sappnd",	"AppendOnly"},
 +		{ "sappend",	"AppendOnly"},
 +		{ "schg",	"Immutable"},
 +		{ "schange",	"Immutable"},
 +		{ "simmutable",	"Immutable"},
 +		{ "nodump",	"NoDump"},
 +		{ "nouunlnk",	"Undelete"},
 +		{ "nouunlink",	"Undelete"},
 +		{ "btree",	"BTree"},
 +		{ "comperr",	"CompError"},
 +		{ "compress",	"Compress"},
 +		{ "noatime",	"NoAtime"},
 +		{ "compdirty",	"CompDirty"},
 +		{ "comprblk",	"CompBlock"},
 +		{ "dirsync",	"DirSync"},
 +		{ "hashidx",	"HashIndexed"},
 +		{ "imagic",	"iMagic"},
 +		{ "journal",	"Journaled"},
 +		{ "securedeletion",	"SecureDeletion"},
 +		{ "sync",	"Synchronous"},
 +		{ "notail",	"NoTail"},
 +		{ "topdir",	"TopDir"},
 +		{ "reserved",	"Reserved"},
 +		{ NULL, NULL}
 +	};
 +	const struct flagentry *fe, *flagentry;
 +#define FLAGENTRY_MAXSIZE ((sizeof(flagbsd)+sizeof(flagext2))/sizeof(flagbsd))
 +	const struct flagentry *avail[FLAGENTRY_MAXSIZE];
 +	const char *p;
 +	int i, n, r;
 +
 +	if (strcmp(element, "ext2") == 0)
 +		flagentry = flagext2;
 +	else
 +		flagentry = flagbsd;
 +	n = 0;
 +	p = fflags_text;
 +	do {
 +		const char *cp;
 +
 +		cp = strchr(p, ',');
 +		if (cp == NULL)
 +			cp = p + strlen(p);
 +
 +		for (fe = flagentry; fe->name != NULL; fe++) {
 +			if (fe->name[cp - p] != '\0'
 +			    || p[0] != fe->name[0])
 +				continue;
 +			if (strncmp(p, fe->name, cp - p) == 0) {
 +				avail[n++] = fe;
 +				break;
 +			}
 +		}
 +		if (*cp == ',')
 +			p = cp + 1;
 +		else
 +			p = NULL;
 +	} while (p != NULL);
 +
 +	if (n > 0) {
 +		r = xmlTextWriterStartElement(writer, BAD_CAST(element));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		for (i = 0; i < n; i++) {
 +			r = xmlwrite_string(a, writer,
 +			    avail[i]->xarname, NULL);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +		}
 +
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +make_file_entry(struct archive_write *a, xmlTextWriterPtr writer,
 +    struct file *file)
 +{
 +	struct xar *xar;
 +	const char *filetype, *filelink, *fflags;
 +	struct archive_string linkto;
 +	struct heap_data *heap;
 +	unsigned char *tmp;
 +	const char *p;
 +	size_t len;
 +	int r, r2, l, ll;
 +
 +	xar = (struct xar *)a->format_data;
 +	r2 = ARCHIVE_OK;
 +
 +	/*
 +	 * Make a file name entry, "<name>".
 +	 */
 +	l = ll = archive_strlen(&(file->basename));
 +	tmp = malloc(l);
 +	if (tmp == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	r = UTF8Toisolat1(tmp, &l, BAD_CAST(file->basename.s), &ll);
 +	free(tmp);
 +	if (r < 0) {
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("name"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlTextWriterWriteAttribute(writer,
 +		    BAD_CAST("enctype"), BAD_CAST("base64"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteAttribute() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlTextWriterWriteBase64(writer, file->basename.s,
 +		    0, archive_strlen(&(file->basename)));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteBase64() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	} else {
 +		r = xmlwrite_string(a, writer, "name", file->basename.s);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a file type entry, "<type>".
 +	 */
 +	filelink = NULL;
 +	archive_string_init(&linkto);
 +	switch (archive_entry_filetype(file->entry)) {
 +	case AE_IFDIR:
 +		filetype = "directory"; break;
 +	case AE_IFLNK:
 +		filetype = "symlink"; break;
 +	case AE_IFCHR:
 +		filetype = "character special"; break;
 +	case AE_IFBLK:
 +		filetype = "block special"; break;
 +	case AE_IFSOCK:
 +		filetype = "socket"; break;
 +	case AE_IFIFO:
 +		filetype = "fifo"; break;
 +	case AE_IFREG:
 +	default:
 +		if (file->hardlink_target != NULL) {
 +			filetype = "hardlink";
 +			filelink = "link";
 +			if (file->hardlink_target == file)
 +				archive_strcpy(&linkto, "original");
 +			else
 +				archive_string_sprintf(&linkto, "%d",
 +				    file->hardlink_target->id);
 +		} else
 +			filetype = "file";
 +		break;
 +	}
 +	r = xmlwrite_string_attr(a, writer, "type", filetype,
 +	    filelink, linkto.s);
 +	archive_string_free(&linkto);
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +
 +	/*
 +	 * On a virtual directory, we record "name" and "type" only.
 +	 */
 +	if (file->virtual)
 +		return (ARCHIVE_OK);
 +
 +	switch (archive_entry_filetype(file->entry)) {
 +	case AE_IFLNK:
 +		/*
 +		 * xar utility has checked a file type, which
 +		 * a symblic-link file has referenced.
 +		 * For example:
 +		 *   <link type="directory">../ref/</link>
 +		 *   The symlink target file is "../ref/" and its
 +		 *   file type is a directory.
 +		 *
 +		 *   <link type="file">../f</link>
 +		 *   The symlink target file is "../f" and its
 +		 *   file type is a regular file.
 +		 *
 +		 * But our implemention cannot do it, and then we
 +		 * always record that a attribute "type" is "borken",
 +		 * for example:
 +		 *   <link type="broken">foo/bar</link>
 +		 *   It means "foo/bar" is not reachable.
 +		 */
 +		r = xmlwrite_string_attr(a, writer, "link",
 +		    file->symlink.s,
 +		    "type", "broken");
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +		break;
 +	case AE_IFCHR:
 +	case AE_IFBLK:
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("device"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlwrite_fstring(a, writer, "major",
 +		    "%d", archive_entry_rdevmajor(file->entry));
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +		r = xmlwrite_fstring(a, writer, "minor",
 +		    "%d", archive_entry_rdevminor(file->entry));
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		break;
 +	default:
 +		break;
 +	}
 +
 +	/*
 +	 * Make a inode entry, "<inode>".
 +	 */
 +	r = xmlwrite_fstring(a, writer, "inode",
 +	    "%jd", archive_entry_ino64(file->entry));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	if (archive_entry_dev(file->entry) != 0) {
 +		r = xmlwrite_fstring(a, writer, "deviceno",
 +		    "%d", archive_entry_dev(file->entry));
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a file mode entry, "<mode>".
 +	 */
 +	r = xmlwrite_mode(a, writer, "mode",
 +	    archive_entry_mode(file->entry));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +
 +	/*
 +	 * Make a user entry, "<uid>" and "<user>.
 +	 */
 +	r = xmlwrite_fstring(a, writer, "uid",
 +	    "%d", archive_entry_uid(file->entry));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = archive_entry_uname_l(file->entry, &p, &len, xar->sconv);
 +	if (r != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Uname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Can't translate uname '%s' to UTF-8",
 +		    archive_entry_uname(file->entry));
 +		r2 = ARCHIVE_WARN;
 +	}
 +	if (len > 0) {
 +		r = xmlwrite_string(a, writer, "user", p);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a group entry, "<gid>" and "<group>.
 +	 */
 +	r = xmlwrite_fstring(a, writer, "gid",
 +	    "%d", archive_entry_gid(file->entry));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = archive_entry_gname_l(file->entry, &p, &len, xar->sconv);
 +	if (r != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Gname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Can't translate gname '%s' to UTF-8",
 +		    archive_entry_gname(file->entry));
 +		r2 = ARCHIVE_WARN;
 +	}
 +	if (len > 0) {
 +		r = xmlwrite_string(a, writer, "group", p);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a ctime entry, "<ctime>".
 +	 */
 +	if (archive_entry_ctime_is_set(file->entry)) {
 +		r = xmlwrite_time(a, writer, "ctime",
 +		    archive_entry_ctime(file->entry), 1);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a mtime entry, "<mtime>".
 +	 */
 +	if (archive_entry_mtime_is_set(file->entry)) {
 +		r = xmlwrite_time(a, writer, "mtime",
 +		    archive_entry_mtime(file->entry), 1);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a atime entry, "<atime>".
 +	 */
 +	if (archive_entry_atime_is_set(file->entry)) {
 +		r = xmlwrite_time(a, writer, "atime",
 +		    archive_entry_atime(file->entry), 1);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make fflags entries, "<flags>" and "<ext2>".
 +	 */
 +	fflags = archive_entry_fflags_text(file->entry);
 +	if (fflags != NULL) {
 +		r = make_fflags_entry(a, writer, "flags", fflags);
 +		if (r < 0)
 +			return (r);
 +		r = make_fflags_entry(a, writer, "ext2", fflags);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/*
 +	 * Make extended attribute entries, "<ea>".
 +	 */
 +	archive_entry_xattr_reset(file->entry);
 +	for (heap = file->xattr.first; heap != NULL; heap = heap->next) {
 +		const char *name;
 +		const void *value;
 +		size_t size;
 +
 +		archive_entry_xattr_next(file->entry,
 +		    &name, &value, &size);
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("ea"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlTextWriterWriteFormatAttribute(writer,
 +		    BAD_CAST("id"), "%d", heap->id);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteAttribute() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlwrite_heap(a, writer, heap);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +		r = xmlwrite_string(a, writer, "name", name);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	/*
 +	 * Make a file data entry, "<data>".
 +	 */
 +	if (file->data.length > 0) {
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("data"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		r = xmlwrite_heap(a, writer, &(file->data));
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	if (archive_strlen(&file->script) > 0) {
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("content"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		r = xmlwrite_string(a, writer,
 +		    "interpreter", file->script.s);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +
 +		r = xmlwrite_string(a, writer, "type", "script");
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	return (r2);
 +}
 +
 +/*
 + * Make the TOC
 + */
 +static int
 +make_toc(struct archive_write *a)
 +{
 +	struct xar *xar;
 +	struct file *np;
 +	xmlBufferPtr bp;
 +	xmlTextWriterPtr writer;
 +	int algsize;
 +	int r, ret;
 +
 +	xar = (struct xar *)a->format_data;
 +
 +	ret = ARCHIVE_FATAL;
 +
 +	/*
 +	 * Initialize xml writer.
 +	 */
 +	writer = NULL;
 +	bp = xmlBufferCreate();
 +	if (bp == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "xmlBufferCreate() "
 +		    "couldn't create xml buffer");
 +		goto exit_toc;
 +	}
 +	writer = xmlNewTextWriterMemory(bp, 0);
 +	if (writer == NULL) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlNewTextWriterMemory() "
 +		    "couldn't create xml writer");
 +		goto exit_toc;
 +	}
 +	r = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterStartDocument() failed: %d", r);
 +		goto exit_toc;
 +	}
 +	r = xmlTextWriterSetIndent(writer, 4);
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterSetIndent() failed: %d", r);
 +		goto exit_toc;
 +	}
 +
 +	/*
 +	 * Start recoding TOC
 +	 */
 +	r = xmlTextWriterStartElement(writer, BAD_CAST("xar"));
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterStartElement() failed: %d", r);
 +		goto exit_toc;
 +	}
 +	r = xmlTextWriterStartElement(writer, BAD_CAST("toc"));
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterStartDocument() failed: %d", r);
 +		goto exit_toc;
 +	}
 +
 +	/*
 +	 * Record the creation time of the archive file.
 +	 */
 +	r = xmlwrite_time(a, writer, "creation-time", time(NULL), 0);
 +	if (r < 0)
 +		goto exit_toc;
 +
 +	/*
 +	 * Record the checksum value of TOC
 +	 */
 +	algsize = getalgsize(xar->opt_toc_sumalg);
 +	if (algsize) {
 +		/*
 +		 * Record TOC checksum
 +		 */
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("checksum"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			goto exit_toc;
 +		}
 +		r = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"),
 +		    BAD_CAST(getalgname(xar->opt_toc_sumalg)));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteAttribute() failed: %d", r);
 +			goto exit_toc;
 +		}
 +
 +		/*
 +		 * Record the offset of the value of checksum of TOC
 +		 */
 +		r = xmlwrite_string(a, writer, "offset", "0");
 +		if (r < 0)
 +			goto exit_toc;
 +
 +		/*
 +		 * Record the size of the value of checksum of TOC
 +		 */
 +		r = xmlwrite_fstring(a, writer, "size", "%d", algsize);
 +		if (r < 0)
 +			goto exit_toc;
 +
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			goto exit_toc;
 +		}
 +	}
 +
 +	np = xar->root;
 +	do {
 +		if (np != np->parent) {
 +			r = make_file_entry(a, writer, np);
 +			if (r != ARCHIVE_OK)
 +				goto exit_toc;
 +		}
 +
 +		if (np->dir && np->children.first != NULL) {
 +			/* Enter to sub directories. */
 +			np = np->children.first;
 +			r = xmlTextWriterStartElement(writer,
 +			    BAD_CAST("file"));
 +			if (r < 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "xmlTextWriterStartElement() "
 +				    "failed: %d", r);
 +				goto exit_toc;
 +			}
 +			r = xmlTextWriterWriteFormatAttribute(
 +			    writer, BAD_CAST("id"), "%d", np->id);
 +			if (r < 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "xmlTextWriterWriteAttribute() "
 +				    "failed: %d", r);
 +				goto exit_toc;
 +			}
 +			continue;
 +		}
 +		while (np != np->parent) {
 +			r = xmlTextWriterEndElement(writer);
 +			if (r < 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "xmlTextWriterEndElement() "
 +				    "failed: %d", r);
 +				goto exit_toc;
 +			}
 +			if (np->chnext == NULL) {
 +				/* Return to the parent directory. */
 +				np = np->parent;
 +			} else {
 +				np = np->chnext;
 +				r = xmlTextWriterStartElement(writer,
 +				    BAD_CAST("file"));
 +				if (r < 0) {
 +					archive_set_error(&a->archive,
 +					    ARCHIVE_ERRNO_MISC,
 +					    "xmlTextWriterStartElement() "
 +					    "failed: %d", r);
 +					goto exit_toc;
 +				}
 +				r = xmlTextWriterWriteFormatAttribute(
 +				    writer, BAD_CAST("id"), "%d", np->id);
 +				if (r < 0) {
 +					archive_set_error(&a->archive,
 +					    ARCHIVE_ERRNO_MISC,
 +					    "xmlTextWriterWriteAttribute() "
 +					    "failed: %d", r);
 +					goto exit_toc;
 +				}
 +				break;
 +			}
 +		}
 +	} while (np != np->parent);
 +
 +	r = xmlTextWriterEndDocument(writer);
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterEndDocument() failed: %d", r);
 +		goto exit_toc;
 +	}
 +#if DEBUG_PRINT_TOC
 +	fprintf(stderr, "\n---TOC-- %d bytes --\n%s\n",
 +	    strlen((const char *)bp->content), bp->content);
 +#endif
 +
 +	/*
 +	 * Compress the TOC and calculate the sum of the TOC.
 +	 */
 +	xar->toc.temp_offset = xar->temp_offset;
 +	xar->toc.size = bp->use;
 +	checksum_init(&(xar->a_sumwrk), xar->opt_toc_sumalg);
 +
 +	r = compression_init_encoder_gzip(&(a->archive),
 +	    &(xar->stream), 6, 1);
 +	if (r != ARCHIVE_OK)
 +		goto exit_toc;
 +	xar->stream.next_in = bp->content;
 +	xar->stream.avail_in = bp->use;
 +	xar->stream.total_in = 0;
 +	xar->stream.next_out = xar->wbuff;
 +	xar->stream.avail_out = sizeof(xar->wbuff);
 +	xar->stream.total_out = 0;
 +	for (;;) {
 +		size_t size;
 +
 +		r = compression_code(&(a->archive),
 +		    &(xar->stream), ARCHIVE_Z_FINISH);
 +		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
 +			goto exit_toc;
 +		size = sizeof(xar->wbuff) - xar->stream.avail_out;
 +		checksum_update(&(xar->a_sumwrk), xar->wbuff, size);
 +		if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)
 +			goto exit_toc;
 +		if (r == ARCHIVE_EOF)
 +			break;
 +		xar->stream.next_out = xar->wbuff;
 +		xar->stream.avail_out = sizeof(xar->wbuff);
 +	}
 +	r = compression_end(&(a->archive), &(xar->stream));
 +	if (r != ARCHIVE_OK)
 +		goto exit_toc;
 +	xar->toc.length = xar->stream.total_out;
 +	xar->toc.compression = GZIP;
 +	checksum_final(&(xar->a_sumwrk), &(xar->toc.a_sum));
 +
 +	ret = ARCHIVE_OK;
 +exit_toc:
 +	if (writer)
 +		xmlFreeTextWriter(writer);
 +	if (bp)
 +		xmlBufferFree(bp);
 +
 +	return (ret);
 +}
 +
 +static int
 +flush_wbuff(struct archive_write *a)
 +{
 +	struct xar *xar;
 +	int r;
 +	size_t s;
 +
 +	xar = (struct xar *)a->format_data;
 +	s = sizeof(xar->wbuff) - xar->wbuff_remaining;
 +	r = __archive_write_output(a, xar->wbuff, s);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	xar->wbuff_remaining = sizeof(xar->wbuff);
 +	return (r);
 +}
 +
 +static int
 +copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
 +{
 +	struct xar *xar;
 +	int r;
 +
 +	xar = (struct xar *)a->format_data;
 +	if (lseek(xar->temp_fd, offset, SEEK_SET) < 0) {
 +		archive_set_error(&(a->archive), errno, "lseek failed");
 +		return (ARCHIVE_FATAL);
 +	}
 +	while (length) {
 +		size_t rsize;
 +		ssize_t rs;
 +		unsigned char *wb;
 +
 +		if (length > xar->wbuff_remaining)
 +			rsize = xar->wbuff_remaining;
 +		else
 +			rsize = (size_t)length;
 +		wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
 +		rs = read(xar->temp_fd, wb, rsize);
 +		if (rs < 0) {
 +			archive_set_error(&(a->archive), errno,
 +			    "Can't read temporary file(%jd)",
 +			    (intmax_t)rs);
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (rs == 0) {
 +			archive_set_error(&(a->archive), 0,
 +			    "Truncated xar archive");
 +			return (ARCHIVE_FATAL);
 +		}
 +		xar->wbuff_remaining -= rs;
 +		length -= rs;
 +		if (xar->wbuff_remaining == 0) {
 +			r = flush_wbuff(a);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +		}
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xar_close(struct archive_write *a)
 +{
 +	struct xar *xar;
 +	unsigned char *wb;
 +	uint64_t length;
 +	int r;
 +
 +	xar = (struct xar *)a->format_data;
 +
 +	/* Empty! */
 +	if (xar->root->children.first == NULL)
 +		return (ARCHIVE_OK);
 +
 +	/* Save the length of all file extended attributes and contents. */
 +	length = xar->temp_offset;
 +
 +	/* Connect hardlinked files */
 +	file_connect_hardlink_files(xar);
 +
 +	/* Make the TOC */
 +	r = make_toc(a);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/*
 +	 * Make the xar header on wbuff(write buffer).
 +	 */
 +	wb = xar->wbuff;
 +	xar->wbuff_remaining = sizeof(xar->wbuff);
 +	archive_be32enc(&wb[0], HEADER_MAGIC);
 +	archive_be16enc(&wb[4], HEADER_SIZE);
 +	archive_be16enc(&wb[6], HEADER_VERSION);
 +	archive_be64enc(&wb[8], xar->toc.length);
 +	archive_be64enc(&wb[16], xar->toc.size);
 +	archive_be32enc(&wb[24], xar->toc.a_sum.alg);
 +	xar->wbuff_remaining -= HEADER_SIZE;
 +
 +	/*
 +	 * Write the TOC
 +	 */
 +	r = copy_out(a, xar->toc.temp_offset, xar->toc.length);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +
 +	/* Write the checksum value of the TOC. */
 +	if (xar->toc.a_sum.len) {
 +		if (xar->wbuff_remaining < xar->toc.a_sum.len) {
 +			r = flush_wbuff(a);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +		}
 +		wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
 +		memcpy(wb, xar->toc.a_sum.val, xar->toc.a_sum.len);
 +		xar->wbuff_remaining -= xar->toc.a_sum.len;
 +	}
 +
 +	/*
 +	 * Write all file extended attributes and contents.
 +	 */
 +	r = copy_out(a, xar->toc.a_sum.len, length);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	r = flush_wbuff(a);
 +	return (r);
 +}
 +
 +static int
 +xar_free(struct archive_write *a)
 +{
 +	struct xar *xar;
 +
 +	xar = (struct xar *)a->format_data;
 +	archive_string_free(&(xar->cur_dirstr));
 +	archive_string_free(&(xar->tstr));
 +	archive_string_free(&(xar->vstr));
 +	file_free_hardlinks(xar);
 +	file_free_register(xar);
 +	compression_end(&(a->archive), &(xar->stream));
 +	free(xar);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +file_cmp_node(const struct archive_rb_node *n1,
 +    const struct archive_rb_node *n2)
 +{
 +	struct file *f1 = (struct file *)n1;
 +	struct file *f2 = (struct file *)n2;
 +
 +	return (strcmp(f1->basename.s, f2->basename.s));
 +}
 +        
 +static int
 +file_cmp_key(const struct archive_rb_node *n, const void *key)
 +{
 +	struct file *f = (struct file *)n;
 +
 +	return (strcmp(f->basename.s, (const char *)key));
 +}
 +
 +static struct file *
 +file_new(struct archive_write *a, struct archive_entry *entry)
 +{
 +	struct file *file;
 +	static const struct archive_rb_tree_ops rb_ops = {
 +		file_cmp_node, file_cmp_key
 +	};
 +
 +	file = calloc(1, sizeof(*file));
 +	if (file == NULL)
 +		return (NULL);
 +
 +	if (entry != NULL)
 +		file->entry = archive_entry_clone(entry);
 +	else
 +		file->entry = archive_entry_new2(&a->archive);
 +	if (file->entry == NULL) {
 +		free(file);
 +		return (NULL);
 +	}
 +	__archive_rb_tree_init(&(file->rbtree), &rb_ops);
 +	file->children.first = NULL;
 +	file->children.last = &(file->children.first);
 +	file->xattr.first = NULL;
 +	file->xattr.last = &(file->xattr.first);
 +	archive_string_init(&(file->parentdir));
 +	archive_string_init(&(file->basename));
 +	archive_string_init(&(file->symlink));
 +	archive_string_init(&(file->script));
 +	if (entry != NULL && archive_entry_filetype(entry) == AE_IFDIR)
 +		file->dir = 1;
 +
 +	return (file);
 +}
 +
 +static void
 +file_free(struct file *file)
 +{
 +	struct heap_data *heap, *next_heap;
 +
 +	heap = file->xattr.first;
 +	while (heap != NULL) {
 +		next_heap = heap->next;
 +		free(heap);
 +		heap = next_heap;
 +	}
 +	archive_string_free(&(file->parentdir));
 +	archive_string_free(&(file->basename));
 +	archive_string_free(&(file->symlink));
 +	archive_string_free(&(file->script));
 +	free(file);
 +}
 +
 +static struct file *
 +file_create_virtual_dir(struct archive_write *a, struct xar *xar,
 +    const char *pathname)
 +{
 +	struct file *file;
 +
 +	file = file_new(a, NULL);
 +	if (file == NULL)
 +		return (NULL);
 +	archive_entry_set_pathname(file->entry, pathname);
 +	archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
 +
 +	file->dir = 1;
 +	file->virtual = 1;
 +
 +	return (file);
 +}
 +
 +static int
 +file_add_child_tail(struct file *parent, struct file *child)
 +{
 +	if (!__archive_rb_tree_insert_node(
 +	    &(parent->rbtree), (struct archive_rb_node *)child))
 +		return (0);
 +	child->chnext = NULL;
 +	*parent->children.last = child;
 +	parent->children.last = &(child->chnext);
 +	child->parent = parent;
 +	return (1);
 +}
 +
 +/*
 + * Find a entry from `parent'
 + */
 +static struct file *
 +file_find_child(struct file *parent, const char *child_name)
 +{
 +	struct file *np;
 +
 +	np = (struct file *)__archive_rb_tree_find_node(
 +	    &(parent->rbtree), child_name);
 +	return (np);
 +}
 +
 +#if defined(_WIN32) || defined(__CYGWIN__)
 +static void
 +cleanup_backslash(char *utf8, size_t len)
 +{
 +
 +	/* Convert a path-separator from '\' to  '/' */
 +	while (*utf8 != '\0' && len) {
 +		if (*utf8 == '\\')
 +			*utf8 = '/';
 +		++utf8;
 +		--len;
 +	}
 +}
 +#else
 +#define cleanup_backslash(p, len)	/* nop */
 +#endif
 +
 +/*
 + * Generate a parent directory name and a base name from a pathname.
 + */
 +static int
 +file_gen_utility_names(struct archive_write *a, struct file *file)
 +{
 +	struct xar *xar;
 +	const char *pp;
 +	char *p, *dirname, *slash;
 +	size_t len;
 +	int r = ARCHIVE_OK;
 +
 +	xar = (struct xar *)a->format_data;
 +	archive_string_empty(&(file->parentdir));
 +	archive_string_empty(&(file->basename));
 +	archive_string_empty(&(file->symlink));
 +
 +	if (file->parent == file)/* virtual root */
 +		return (ARCHIVE_OK);
 +
 +	if (archive_entry_pathname_l(file->entry, &pp, &len, xar->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,
 +		    "Can't translate pathname '%s' to UTF-8",
 +		    archive_entry_pathname(file->entry));
 +		r = ARCHIVE_WARN;
 +	}
 +	archive_strncpy(&(file->parentdir), pp, len);
 +	len = file->parentdir.length;
 +	p = dirname = file->parentdir.s;
 +	/*
 +	 * Convert a path-separator from '\' to  '/'
 +	 */
 +	cleanup_backslash(p, len);
 +
 +	/*
 +	 * Remove leading '/', '../' and './' elements
 +	 */
 +	while (*p) {
 +		if (p[0] == '/') {
 +			p++;
 +			len--;
 +		} else if (p[0] != '.')
 +			break;
 +		else if (p[1] == '.' && p[2] == '/') {
 +			p += 3;
 +			len -= 3;
 +		} else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
 +			p += 2;
 +			len -= 2;
 +		} else if (p[1] == '\0') {
 +			p++;
 +			len--;
 +		} else
 +			break;
 +	}
 +	if (p != dirname) {
 +		memmove(dirname, p, len+1);
 +		p = dirname;
 +	}
 +	/*
 +	 * Remove "/","/." and "/.." elements from tail.
 +	 */
 +	while (len > 0) {
 +		size_t ll = len;
 +
 +		if (len > 0 && p[len-1] == '/') {
 +			p[len-1] = '\0';
 +			len--;
 +		}
 +		if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
 +			p[len-2] = '\0';
 +			len -= 2;
 +		}
 +		if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
 +		    p[len-1] == '.') {
 +			p[len-3] = '\0';
 +			len -= 3;
 +		}
 +		if (ll == len)
 +			break;
 +	}
 +	while (*p) {
 +		if (p[0] == '/') {
 +			if (p[1] == '/')
 +				/* Convert '//' --> '/' */
 +				strcpy(p, p+1);
 +			else if (p[1] == '.' && p[2] == '/')
 +				/* Convert '/./' --> '/' */
 +				strcpy(p, p+2);
 +			else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
 +				/* Convert 'dir/dir1/../dir2/'
 +				 *     --> 'dir/dir2/'
 +				 */
 +				char *rp = p -1;
 +				while (rp >= dirname) {
 +					if (*rp == '/')
 +						break;
 +					--rp;
 +				}
 +				if (rp > dirname) {
 +					strcpy(rp, p+3);
 +					p = rp;
 +				} else {
 +					strcpy(dirname, p+4);
 +					p = dirname;
 +				}
 +			} else
 +				p++;
 +		} else
 +			p++;
 +	}
 +	p = dirname;
 +	len = strlen(p);
 +
 +	if (archive_entry_filetype(file->entry) == AE_IFLNK) {
 +		size_t len2;
 +		/* Convert symlink name too. */
 +		if (archive_entry_symlink_l(file->entry, &pp, &len2,
 +		    xar->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,
 +			    "Can't translate symlink '%s' to UTF-8",
 +			    archive_entry_symlink(file->entry));
 +			r = ARCHIVE_WARN;
 +		}
 +		archive_strncpy(&(file->symlink), pp, len2);
 +		cleanup_backslash(file->symlink.s, file->symlink.length);
 +	}
 +	/*
 +	 * - Count up directory elements.
 +	 * - Find out the position which points the last position of
 +	 *   path separator('/').
 +	 */
 +	slash = NULL;
 +	for (; *p != '\0'; p++)
 +		if (*p == '/')
 +			slash = p;
 +	if (slash == NULL) {
 +		/* The pathname doesn't have a parent directory. */
 +		file->parentdir.length = len;
 +		archive_string_copy(&(file->basename), &(file->parentdir));
 +		archive_string_empty(&(file->parentdir));
 +		file->parentdir.s = '\0';
 +		return (r);
 +	}
 +
 +	/* Make a basename from dirname and slash */
 +	*slash  = '\0';
 +	file->parentdir.length = slash - dirname;
 +	archive_strcpy(&(file->basename),  slash + 1);
 +	return (r);
 +}
 +
 +static int
 +get_path_component(char *name, int n, const char *fn)
 +{
 +	char *p;
 +	int l;
 +
 +	p = strchr(fn, '/');
 +	if (p == NULL) {
 +		if ((l = strlen(fn)) == 0)
 +			return (0);
 +	} else
 +		l = p - fn;
 +	if (l > n -1)
 +		return (-1);
 +	memcpy(name, fn, l);
 +	name[l] = '\0';
 +
 +	return (l);
 +}
 +
 +/*
 + * Add a new entry into the tree.
 + */
 +static int
 +file_tree(struct archive_write *a, struct file **filepp)
 +{
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +	char name[_MAX_FNAME];/* Included null terminator size. */
 +#elif defined(NAME_MAX) && NAME_MAX >= 255
 +	char name[NAME_MAX+1];
 +#else
 +	char name[256];
 +#endif
 +	struct xar *xar = (struct xar *)a->format_data;
 +	struct file *dent, *file, *np;
 +	struct archive_entry *ent;
 +	const char *fn, *p;
 +	int l;
 +
 +	file = *filepp;
 +	dent = xar->root;
 +	if (file->parentdir.length > 0)
 +		fn = p = file->parentdir.s;
 +	else
 +		fn = p = "";
 +
 +	/*
 +	 * If the path of the parent directory of `file' entry is
 +	 * the same as the path of `cur_dirent', add isoent to
 +	 * `cur_dirent'.
 +	 */
 +	if (archive_strlen(&(xar->cur_dirstr))
 +	      == archive_strlen(&(file->parentdir)) &&
 +	    strcmp(xar->cur_dirstr.s, fn) == 0) {
 +		if (!file_add_child_tail(xar->cur_dirent, file)) {
 +			np = (struct file *)__archive_rb_tree_find_node(
 +			    &(xar->cur_dirent->rbtree),
 +			    file->basename.s);
 +			goto same_entry;
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +
 +	for (;;) {
 +		l = get_path_component(name, sizeof(name), fn);
 +		if (l == 0) {
 +			np = NULL;
 +			break;
 +		}
 +		if (l < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "A name buffer is too small");
 +			file_free(file);
 +			*filepp = NULL;
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		np = file_find_child(dent, name);
 +		if (np == NULL || fn[0] == '\0')
 +			break;
 +
 +		/* Find next subdirectory. */
 +		if (!np->dir) {
 +			/* NOT Directory! */
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "`%s' is not directory, we cannot insert `%s' ",
 +			    archive_entry_pathname(np->entry),
 +			    archive_entry_pathname(file->entry));
 +			file_free(file);
 +			*filepp = NULL;
 +			return (ARCHIVE_FAILED);
 +		}
 +		fn += l;
 +		if (fn[0] == '/')
 +			fn++;
 +		dent = np;
 +	}
 +	if (np == NULL) {
 +		/*
 +		 * Create virtual parent directories.
 +		 */
 +		while (fn[0] != '\0') {
 +			struct file *vp;
 +			struct archive_string as;
 +
 +			archive_string_init(&as);
 +			archive_strncat(&as, p, fn - p + l);
 +			if (as.s[as.length-1] == '/') {
 +				as.s[as.length-1] = '\0';
 +				as.length--;
 +			}
 +			vp = file_create_virtual_dir(a, xar, as.s);
 +			if (vp == NULL) {
 +				archive_string_free(&as);
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "Can't allocate memory");
 +				file_free(file);
 +				*filepp = NULL;
 +				return (ARCHIVE_FATAL);
 +			}
 +			archive_string_free(&as);
 +			if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED)
 +				return (ARCHIVE_FATAL);
 +			file_add_child_tail(dent, vp);
 +			file_register(xar, vp);
 +			np = vp;
 +
 +			fn += l;
 +			if (fn[0] == '/')
 +				fn++;
 +			l = get_path_component(name, sizeof(name), fn);
 +			if (l < 0) {
 +				archive_string_free(&as);
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "A name buffer is too small");
 +				file_free(file);
 +				*filepp = NULL;
 +				return (ARCHIVE_FATAL);
 +			}
 +			dent = np;
 +		}
 +
 +		/* Found out the parent directory where isoent can be
 +		 * inserted. */
 +		xar->cur_dirent = dent;
 +		archive_string_empty(&(xar->cur_dirstr));
 +		archive_string_ensure(&(xar->cur_dirstr),
 +		    archive_strlen(&(dent->parentdir)) +
 +		    archive_strlen(&(dent->basename)) + 2);
 +		if (archive_strlen(&(dent->parentdir)) +
 +		    archive_strlen(&(dent->basename)) == 0)
 +			xar->cur_dirstr.s[0] = 0;
 +		else {
 +			if (archive_strlen(&(dent->parentdir)) > 0) {
 +				archive_string_copy(&(xar->cur_dirstr),
 +				    &(dent->parentdir));
 +				archive_strappend_char(&(xar->cur_dirstr), '/');
 +			}
 +			archive_string_concat(&(xar->cur_dirstr),
 +			    &(dent->basename));
 +		}
 +
 +		if (!file_add_child_tail(dent, file)) {
 +			np = (struct file *)__archive_rb_tree_find_node(
 +			    &(dent->rbtree), file->basename.s);
 +			goto same_entry;
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +
 +same_entry:
 +	/*
 +	 * We have already has the entry the filename of which is
 +	 * the same.
 +	 */
 +	if (archive_entry_filetype(np->entry) !=
 +	    archive_entry_filetype(file->entry)) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Found duplicate entries `%s' and its file type is "
 +		    "different",
 +		    archive_entry_pathname(np->entry));
 +		file_free(file);
 +		*filepp = NULL;
 +		return (ARCHIVE_FAILED);
 +	}
 +
 +	/* Swap files. */
 +	ent = np->entry;
 +	np->entry = file->entry;
 +	file->entry = ent;
 +	np->virtual = 0;
 +
 +	file_free(file);
 +	*filepp = np;
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +file_register(struct xar *xar, struct file *file)
 +{
 +	file->id = xar->file_idx++;
 +        file->next = NULL;
 +        *xar->file_list.last = file;
 +        xar->file_list.last = &(file->next);
 +}
 +
 +static void
 +file_init_register(struct xar *xar)
 +{
 +	xar->file_list.first = NULL;
 +	xar->file_list.last = &(xar->file_list.first);
 +}
 +
 +static void
 +file_free_register(struct xar *xar)
 +{
 +	struct file *file, *file_next;
 +
 +	file = xar->file_list.first;
 +	while (file != NULL) {
 +		file_next = file->next;
 +		file_free(file);
 +		file = file_next;
 +	}
 +}
 +
 +/*
 + * Register entry to get a hardlink target.
 + */
 +static int
 +file_register_hardlink(struct archive_write *a, struct file *file)
 +{
 +	struct xar *xar = (struct xar *)a->format_data;
 +	struct hardlink *hl;
 +	const char *pathname;
 +
 +	archive_entry_set_nlink(file->entry, 1);
 +	pathname = archive_entry_hardlink(file->entry);
 +	if (pathname == NULL) {
 +		/* This `file` is a hardlink target. */
 +		hl = malloc(sizeof(*hl));
 +		if (hl == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		hl->nlink = 1;
 +		/* A hardlink target must be the first position. */
 +		file->hlnext = NULL;
 +		hl->file_list.first = file;
 +		hl->file_list.last = &(file->hlnext);
 +		__archive_rb_tree_insert_node(&(xar->hardlink_rbtree),
 +		    (struct archive_rb_node *)hl);
 +	} else {
 +		hl = (struct hardlink *)__archive_rb_tree_find_node(
 +		    &(xar->hardlink_rbtree), pathname);
 +		if (hl != NULL) {
 +			/* Insert `file` entry into the tail. */
 +			file->hlnext = NULL;
 +			*hl->file_list.last = file;
 +			hl->file_list.last = &(file->hlnext);
 +			hl->nlink++;
 +		}
 +		archive_entry_unset_size(file->entry);
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Hardlinked files have to have the same location of extent.
 + * We have to find out hardlink target entries for entries which
 + * have a hardlink target name.
 + */
 +static void
 +file_connect_hardlink_files(struct xar *xar)
 +{
 +	struct archive_rb_node *n;
 +	struct hardlink *hl;
 +	struct file *target, *nf;
 +
 +	ARCHIVE_RB_TREE_FOREACH(n, &(xar->hardlink_rbtree)) {
 +		hl = (struct hardlink *)n;
 +
 +		/* The first entry must be a hardlink target. */
 +		target = hl->file_list.first;
 +		archive_entry_set_nlink(target->entry, hl->nlink);
 +		if (hl->nlink > 1)
 +			/* It means this file is a hardlink
 +			 * targe itself. */
 +			target->hardlink_target = target;
 +		for (nf = target->hlnext;
 +		    nf != NULL; nf = nf->hlnext) {
 +			nf->hardlink_target = target;
 +			archive_entry_set_nlink(nf->entry, hl->nlink);
 +		}
 +	}
 +}
 +
 +static int
 +file_hd_cmp_node(const struct archive_rb_node *n1,
 +    const struct archive_rb_node *n2)
 +{
 +	struct hardlink *h1 = (struct hardlink *)n1;
 +	struct hardlink *h2 = (struct hardlink *)n2;
 +
 +	return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
 +		       archive_entry_pathname(h2->file_list.first->entry)));
 +}
 +
 +static int
 +file_hd_cmp_key(const struct archive_rb_node *n, const void *key)
 +{
 +	struct hardlink *h = (struct hardlink *)n;
 +
 +	return (strcmp(archive_entry_pathname(h->file_list.first->entry),
 +		       (const char *)key));
 +}
 +
 +
 +static void
 +file_init_hardlinks(struct xar *xar)
 +{
 +	static const struct archive_rb_tree_ops rb_ops = {
 +		file_hd_cmp_node, file_hd_cmp_key,
 +	};
 + 
 +	__archive_rb_tree_init(&(xar->hardlink_rbtree), &rb_ops);
 +}
 +
 +static void
 +file_free_hardlinks(struct xar *xar)
 +{
 +	struct archive_rb_node *n, *next;
 +
 +	for (n = ARCHIVE_RB_TREE_MIN(&(xar->hardlink_rbtree)); n;) {
 +		next = __archive_rb_tree_iterate(&(xar->hardlink_rbtree),
 +		    n, ARCHIVE_RB_DIR_RIGHT);
 +		free(n);
 +		n = next;
 +	}
 +}
 +
 +static void
 +checksum_init(struct chksumwork *sumwrk, enum sumalg sum_alg)
 +{
 +	sumwrk->alg = sum_alg;
 +	switch (sum_alg) {
 +	case CKSUM_NONE:
 +		break;
 +	case CKSUM_SHA1:
 +		archive_sha1_init(&(sumwrk->sha1ctx));
 +		break;
 +	case CKSUM_MD5:
 +		archive_md5_init(&(sumwrk->md5ctx));
 +		break;
 +	}
 +}
 +
 +static void
 +checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)
 +{
 +
 +	switch (sumwrk->alg) {
 +	case CKSUM_NONE:
 +		break;
 +	case CKSUM_SHA1:
 +		archive_sha1_update(&(sumwrk->sha1ctx), buff, size);
 +		break;
 +	case CKSUM_MD5:
 +		archive_md5_update(&(sumwrk->md5ctx), buff, size);
 +		break;
 +	}
 +}
 +
 +static void
 +checksum_final(struct chksumwork *sumwrk, struct chksumval *sumval)
 +{
 +
 +	switch (sumwrk->alg) {
 +	case CKSUM_NONE:
 +		sumval->len = 0;
 +		break;
 +	case CKSUM_SHA1:
 +		archive_sha1_final(&(sumwrk->sha1ctx), sumval->val);
 +		sumval->len = SHA1_SIZE;
 +		break;
 +	case CKSUM_MD5:
 +		archive_md5_final(&(sumwrk->md5ctx), sumval->val);
 +		sumval->len = MD5_SIZE;
 +		break;
 +	}
 +	sumval->alg = sumwrk->alg;
 +}
 +
 +#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
 +static int
 +compression_unsupported_encoder(struct archive *a,
 +    struct la_zstream *lastrm, const char *name)
 +{
 +
 +	archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +	    "%s compression not supported on this platform", name);
 +	lastrm->valid = 0;
 +	lastrm->real_stream = NULL;
 +	return (ARCHIVE_FAILED);
 +}
 +#endif
 +
 +static int
 +compression_init_encoder_gzip(struct archive *a,
 +    struct la_zstream *lastrm, int level, int withheader)
 +{
 +	z_stream *strm;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for gzip stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	/* zlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in = lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out = lastrm->total_out;
 +	if (deflateInit2(strm, level, Z_DEFLATED,
 +	    (withheader)?15:-15,
 +	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lastrm->real_stream = strm;
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_gzip;
 +	lastrm->end = compression_end_gzip;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_gzip(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	z_stream *strm;
 +	int r;
 +
 +	strm = (z_stream *)lastrm->real_stream;
 +	/* zlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in = lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out = lastrm->total_out;
 +	r = deflate(strm,
 +	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
 +	lastrm->next_in = strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in = strm->total_in;
 +	lastrm->next_out = strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out = strm->total_out;
 +	switch (r) {
 +	case Z_OK:
 +		return (ARCHIVE_OK);
 +	case Z_STREAM_END:
 +		return (ARCHIVE_EOF);
 +	default:
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "GZip compression failed:"
 +		    " deflate() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_gzip(struct archive *a, struct la_zstream *lastrm)
 +{
 +	z_stream *strm;
 +	int r;
 +
 +	strm = (z_stream *)lastrm->real_stream;
 +	r = deflateEnd(strm);
 +	free(strm);
 +	lastrm->real_stream = NULL;
 +	lastrm->valid = 0;
 +	if (r != Z_OK) {
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up compressor");
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +static int
 +compression_init_encoder_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	bz_stream *strm;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for bzip2 stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	/* bzlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
 +	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
 +	strm->next_out = (char *)lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
 +	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
 +	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lastrm->real_stream = strm;
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_bzip2;
 +	lastrm->end = compression_end_bzip2;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	bz_stream *strm;
 +	int r;
 +
 +	strm = (bz_stream *)lastrm->real_stream;
 +	/* bzlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
 +	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
 +	strm->next_out = (char *)lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
 +	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
 +	r = BZ2_bzCompress(strm,
 +	    (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
 +	lastrm->next_in = (const unsigned char *)strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in =
 +	    (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
 +	    + (uint64_t)(uint32_t)strm->total_in_lo32;
 +	lastrm->next_out = (unsigned char *)strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out =
 +	    (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
 +	    + (uint64_t)(uint32_t)strm->total_out_lo32;
 +	switch (r) {
 +	case BZ_RUN_OK:     /* Non-finishing */
 +	case BZ_FINISH_OK:  /* Finishing: There's more work to do */
 +		return (ARCHIVE_OK);
 +	case BZ_STREAM_END: /* Finishing: all done */
 +		/* Only occurs in finishing case */
 +		return (ARCHIVE_EOF);
 +	default:
 +		/* Any other return value indicates an error */
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Bzip2 compression failed:"
 +		    " BZ2_bzCompress() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
 +{
 +	bz_stream *strm;
 +	int r;
 +
 +	strm = (bz_stream *)lastrm->real_stream;
 +	r = BZ2_bzCompressEnd(strm);
 +	free(strm);
 +	lastrm->real_stream = NULL;
 +	lastrm->valid = 0;
 +	if (r != BZ_OK) {
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up compressor");
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +#else
 +static int
 +compression_init_encoder_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "bzip2"));
 +}
 +#endif
 +
 +#if defined(HAVE_LZMA_H)
 +static int
 +compression_init_encoder_lzma(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
 +	lzma_stream *strm;
 +	lzma_options_lzma lzma_opt;
 +	int r;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	if (lzma_lzma_preset(&lzma_opt, level)) {
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for lzma stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	*strm = lzma_init_data;
 +	r = lzma_alone_encoder(strm, &lzma_opt);
 +	switch (r) {
 +	case LZMA_OK:
 +		lastrm->real_stream = strm;
 +		lastrm->valid = 1;
 +		lastrm->code = compression_code_lzma;
 +		lastrm->end = compression_end_lzma;
 +		r = ARCHIVE_OK;
 +		break;
 +	case LZMA_MEM_ERROR:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library: "
 +		    "Cannot allocate memory");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +        default:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library: "
 +		    "It's a bug in liblzma");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +	}
 +	return (r);
 +}
 +
 +static int
 +compression_init_encoder_xz(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
 +	lzma_stream *strm;
 +	lzma_filter *lzmafilters;
 +	lzma_options_lzma lzma_opt;
 +	int r;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for xz stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lzmafilters = (lzma_filter *)(strm+1);
 +	if (level > 6)
 +		level = 6;
 +	if (lzma_lzma_preset(&lzma_opt, level)) {
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lzmafilters[0].id = LZMA_FILTER_LZMA2;
 +	lzmafilters[0].options = &lzma_opt;
 +	lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
 +
 +	*strm = lzma_init_data;
 +	r = lzma_stream_encoder(strm, lzmafilters, LZMA_CHECK_CRC64);
 +	switch (r) {
 +	case LZMA_OK:
 +		lastrm->real_stream = strm;
 +		lastrm->valid = 1;
 +		lastrm->code = compression_code_lzma;
 +		lastrm->end = compression_end_lzma;
 +		r = ARCHIVE_OK;
 +		break;
 +	case LZMA_MEM_ERROR:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library: "
 +		    "Cannot allocate memory");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +        default:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library: "
 +		    "It's a bug in liblzma");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +	}
 +	return (r);
 +}
 +
 +static int
 +compression_code_lzma(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	lzma_stream *strm;
 +	int r;
 +
 +	strm = (lzma_stream *)lastrm->real_stream;
 +	strm->next_in = lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in = lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out = lastrm->total_out;
 +	r = lzma_code(strm,
 +	    (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
 +	lastrm->next_in = strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in = strm->total_in;
 +	lastrm->next_out = strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out = strm->total_out;
 +	switch (r) {
 +	case LZMA_OK:
 +		/* Non-finishing case */
 +		return (ARCHIVE_OK);
 +	case LZMA_STREAM_END:
 +		/* This return can only occur in finishing case. */
 +		return (ARCHIVE_EOF);
 +	case LZMA_MEMLIMIT_ERROR:
 +		archive_set_error(a, ENOMEM,
 +		    "lzma compression error:"
 +		    " %ju MiB would have been needed",
 +		    (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
 +			/ (1024 * 1024)));
 +		return (ARCHIVE_FATAL);
 +	default:
 +		/* Any other return value indicates an error */
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "lzma compression failed:"
 +		    " lzma_code() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_lzma(struct archive *a, struct la_zstream *lastrm)
 +{
 +	lzma_stream *strm;
 +
 +	(void)a; /* UNUSED */
 +	strm = (lzma_stream *)lastrm->real_stream;
 +	lzma_end(strm);
 +	free(strm);
 +	lastrm->valid = 0;
 +	lastrm->real_stream = NULL;
 +	return (ARCHIVE_OK);
 +}
 +#else
 +static int
 +compression_init_encoder_lzma(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "lzma"));
 +}
 +static int
 +compression_init_encoder_xz(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "xz"));
 +}
 +#endif
 +
 +static int
 +xar_compression_init_encoder(struct archive_write *a)
 +{
 +	struct xar *xar;
 +	int r;
 +
 +	xar = (struct xar *)a->format_data;
 +	switch (xar->opt_compression) {
 +	case GZIP:
 +		r = compression_init_encoder_gzip(
 +		    &(a->archive), &(xar->stream),
 +		    xar->opt_compression_level, 1);
 +		break;
 +	case BZIP2:
 +		r = compression_init_encoder_bzip2(
 +		    &(a->archive), &(xar->stream),
 +		    xar->opt_compression_level);
 +		break;
 +	case LZMA:
 +		r = compression_init_encoder_lzma(
 +		    &(a->archive), &(xar->stream),
 +		    xar->opt_compression_level);
 +		break;
 +	case XZ:
 +		r = compression_init_encoder_xz(
 +		    &(a->archive), &(xar->stream),
 +		    xar->opt_compression_level);
 +		break;
 +	default:
 +		r = ARCHIVE_OK;
 +		break;
 +	}
 +	if (r == ARCHIVE_OK) {
 +		xar->stream.total_in = 0;
 +		xar->stream.next_out = xar->wbuff;
 +		xar->stream.avail_out = sizeof(xar->wbuff);
 +		xar->stream.total_out = 0;
 +	}
 +
 +	return (r);
 +}
 +
 +static int
 +compression_code(struct archive *a, struct la_zstream *lastrm,
 +    enum la_zaction action)
 +{
 +	if (lastrm->valid)
 +		return (lastrm->code(a, lastrm, action));
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_end(struct archive *a, struct la_zstream *lastrm)
 +{
 +	if (lastrm->valid)
 +		return (lastrm->end(a, lastrm));
 +	return (ARCHIVE_OK);
 +}
 +
 +
 +static int
 +save_xattrs(struct archive_write *a, struct file *file)
 +{
 +	struct xar *xar;
 +	const char *name;
 +	const void *value;
 +	struct heap_data *heap;
 +	size_t size;
 +	int count, r;
 +
 +	xar = (struct xar *)a->format_data;
 +	count = archive_entry_xattr_reset(file->entry);
 +	if (count == 0)
 +		return (ARCHIVE_OK);
 +	while (count--) {
 +		archive_entry_xattr_next(file->entry,
 +		    &name, &value, &size);
 +		checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
 +		checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
 +
 +		heap = calloc(1, sizeof(*heap));
 +		if (heap == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for xattr");
 +			return (ARCHIVE_FATAL);
 +		}
 +		heap->id = file->ea_idx++;
 +		heap->temp_offset = xar->temp_offset;
 +		heap->size = size;/* save a extracted size */
 +		heap->compression = xar->opt_compression;
 +		/* Get a extracted sumcheck value. */
 +		checksum_update(&(xar->e_sumwrk), value, size);
 +		checksum_final(&(xar->e_sumwrk), &(heap->e_sum));
 +
 +		/*
 +		 * Not compression to xattr is simple way.
 +		 */
 +		if (heap->compression == NONE) {
 +			checksum_update(&(xar->a_sumwrk), value, size);
 +			checksum_final(&(xar->a_sumwrk), &(heap->a_sum));
 +			if (write_to_temp(a, value, size)
 +			    != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			heap->length = size;
 +			/* Add heap to the tail of file->xattr. */
 +			heap->next = NULL;
 +			*file->xattr.last = heap;
 +			file->xattr.last = &(heap->next);
 +			/* Next xattr */
 +			continue;
 +		}
 +
 +		/*
 +		 * Init compression library.
 +		 */
 +		r = xar_compression_init_encoder(a);
 +		if (r != ARCHIVE_OK) {
 +			free(heap);
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		xar->stream.next_in = (const unsigned char *)value;
 +		xar->stream.avail_in = size;
 +		for (;;) {
 +			r = compression_code(&(a->archive),
 +			    &(xar->stream), ARCHIVE_Z_FINISH);
 +			if (r != ARCHIVE_OK && r != ARCHIVE_EOF) {
 +				free(heap);
 +				return (ARCHIVE_FATAL);
 +			}
 +			size = sizeof(xar->wbuff) - xar->stream.avail_out;
 +			checksum_update(&(xar->a_sumwrk),
 +			    xar->wbuff, size);
 +			if (write_to_temp(a, xar->wbuff, size)
 +			    != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			if (r == ARCHIVE_OK) {
 +				xar->stream.next_out = xar->wbuff;
 +				xar->stream.avail_out = sizeof(xar->wbuff);
 +			} else {
 +				checksum_final(&(xar->a_sumwrk),
 +				    &(heap->a_sum));
 +				heap->length = xar->stream.total_out;
 +				/* Add heap to the tail of file->xattr. */
 +				heap->next = NULL;
 +				*file->xattr.last = heap;
 +				file->xattr.last = &(heap->next);
 +				break;
 +			}
 +		}
 +		/* Clean up compression library. */
 +		r = compression_end(&(a->archive), &(xar->stream));
 +		if (r != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +getalgsize(enum sumalg sumalg)
 +{
 +	switch (sumalg) {
 +	default:
 +	case CKSUM_NONE:
 +		return (0);
 +	case CKSUM_SHA1:
 +		return (SHA1_SIZE);
 +	case CKSUM_MD5:
 +		return (MD5_SIZE);
 +	}
 +}
 +
 +static const char *
 +getalgname(enum sumalg sumalg)
 +{
 +	switch (sumalg) {
 +	default:
 +	case CKSUM_NONE:
 +		return (NULL);
 +	case CKSUM_SHA1:
 +		return (SHA1_NAME);
 +	case CKSUM_MD5:
 +		return (MD5_NAME);
 +	}
 +}
 +
 +#endif /* Support xar format */
 +
diff --cc Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c
index 3c925d8,0000000..11fbd45
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c
@@@ -1,784 -1,0 +1,820 @@@
 +/*-
 + * Copyright (c) 2008 Anselm Strauss
 + * Copyright (c) 2009 Joerg Sonnenberger
 + * 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.
 + */
 +
 +/*
 + * Development supported by Google Summer of Code 2008.
 + */
 +
 +/*
 + * The current implementation is very limited:
 + *
 + *   - No encryption support.
 + *   - No ZIP64 support.
 + *   - No support for splitting and spanning.
 + *   - Only supports regular file and folder entries.
 + *
 + * Note that generally data in ZIP files is little-endian encoded,
 + * with some exceptions.
 + *
 + * TODO: Since Libarchive is generally 64bit oriented, but this implementation
 + * does not yet support sizes exceeding 32bit, it is highly fragile for
 + * big archives. This should change when ZIP64 is finally implemented, otherwise
 + * some serious checking has to be done.
 + *
 + */
 +
 +#include "archive_platform.h"
 +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_zip.c 201168 2009-12-29 06:15:32Z kientzle $");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_LANGINFO_H
 +#include <langinfo.h>
 +#endif
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STRING_H
 +#include <string.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_endian.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_private.h"
 +#include "archive_write_private.h"
 +
 +#ifndef HAVE_ZLIB_H
 +#include "archive_crc32.h"
 +#endif
 +
 +#define ZIP_SIGNATURE_LOCAL_FILE_HEADER 0x04034b50
 +#define ZIP_SIGNATURE_DATA_DESCRIPTOR 0x08074b50
 +#define ZIP_SIGNATURE_FILE_HEADER 0x02014b50
 +#define ZIP_SIGNATURE_CENTRAL_DIRECTORY_END 0x06054b50
 +#define ZIP_SIGNATURE_EXTRA_TIMESTAMP 0x5455
 +#define ZIP_SIGNATURE_EXTRA_NEW_UNIX 0x7875
 +#define ZIP_VERSION_EXTRACT 0x0014 /* ZIP version 2.0 is needed. */
 +#define ZIP_VERSION_BY 0x0314 /* Made by UNIX, using ZIP version 2.0. */
 +#define ZIP_FLAGS 0x08 /* Flagging bit 3 (count from 0) for using data descriptor. */
 +#define ZIP_FLAGS_UTF8_NAME	(1 << 11)
 +
 +enum compression {
 +	COMPRESSION_STORE = 0
 +#ifdef HAVE_ZLIB_H
 +	,
 +	COMPRESSION_DEFLATE = 8
 +#endif
 +};
 +
- static ssize_t archive_write_zip_data(struct archive_write *, const void *buff, size_t s);
++static ssize_t archive_write_zip_data(struct archive_write *,
++		   const void *buff, size_t s);
 +static int archive_write_zip_close(struct archive_write *);
 +static int archive_write_zip_free(struct archive_write *);
 +static int archive_write_zip_finish_entry(struct archive_write *);
- static int archive_write_zip_header(struct archive_write *, struct archive_entry *);
++static int archive_write_zip_header(struct archive_write *,
++	      struct archive_entry *);
 +static int archive_write_zip_options(struct archive_write *,
 +	      const char *, const char *);
 +static unsigned int dos_time(const time_t);
 +static size_t path_length(struct archive_entry *);
 +static int write_path(struct archive_entry *, struct archive_write *);
 +
 +struct zip_local_file_header {
 +	char signature[4];
 +	char version[2];
 +	char flags[2];
 +	char compression[2];
 +	char timedate[4];
 +	char crc32[4];
 +	char compressed_size[4];
 +	char uncompressed_size[4];
 +	char filename_length[2];
 +	char extra_length[2];
 +};
 +
 +struct zip_file_header {
 +	char signature[4];
 +	char version_by[2];
 +	char version_extract[2];
 +	char flags[2];
 +	char compression[2];
 +	char timedate[4];
 +	char crc32[4];
 +	char compressed_size[4];
 +	char uncompressed_size[4];
 +	char filename_length[2];
 +	char extra_length[2];
 +	char comment_length[2];
 +	char disk_number[2];
 +	char attributes_internal[2];
 +	char attributes_external[4];
 +	char offset[4];
 +};
 +
 +struct zip_data_descriptor {
 +	char signature[4]; /* Not mandatory, but recommended by specification. */
 +	char crc32[4];
 +	char compressed_size[4];
 +	char uncompressed_size[4];
 +};
 +
 +struct zip_extra_data_local {
 +	char time_id[2];
 +	char time_size[2];
 +	char time_flag[1];
 +	char mtime[4];
 +	char atime[4];
 +	char ctime[4];
 +	char unix_id[2];
 +	char unix_size[2];
 +	char unix_version;
 +	char unix_uid_size;
 +	char unix_uid[4];
 +	char unix_gid_size;
 +	char unix_gid[4];
 +};
 +
 +struct zip_extra_data_central {
 +	char time_id[2];
 +	char time_size[2];
 +	char time_flag[1];
 +	char mtime[4];
 +	char unix_id[2];
 +	char unix_size[2];
 +};
 +
 +struct zip_file_header_link {
 +	struct zip_file_header_link *next;
 +	struct archive_entry *entry;
 +	int64_t offset;
 +	unsigned long crc32;
 +	int64_t compressed_size;
 +	enum compression compression;
 +	int flags;
 +};
 +
 +struct zip {
 +	struct zip_data_descriptor data_descriptor;
 +	struct zip_file_header_link *central_directory;
 +	struct zip_file_header_link *central_directory_end;
 +	int64_t offset;
 +	int64_t written_bytes;
 +	int64_t remaining_data_bytes;
 +	enum compression compression;
 +	int flags;
 +	struct archive_string_conv *opt_sconv;
 +	struct archive_string_conv *sconv_default;
 +	int	init_default_conversion;
 +
 +#ifdef HAVE_ZLIB_H
 +	z_stream stream;
 +	size_t len_buf;
 +	unsigned char *buf;
 +#endif
 +};
 +
 +struct zip_central_directory_end {
 +	char signature[4];
 +	char disk[2];
 +	char start_disk[2];
 +	char entries_disk[2];
 +	char entries[2];
 +	char size[4];
 +	char offset[4];
 +	char comment_length[2];
 +};
 +
 +static int
 +archive_write_zip_options(struct archive_write *a, const char *key,
 +    const char *val)
 +{
 +	struct zip *zip = a->format_data;
 +	int ret = ARCHIVE_FAILED;
 +
 +	if (strcmp(key, "compression") == 0) {
 +		if (val == NULL || val[0] == 0) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "%s: compression option needs a compression name",
 +			    a->format_name);
 +		} else if (strcmp(val, "deflate") == 0) {
 +#ifdef HAVE_ZLIB_H
 +			zip->compression = COMPRESSION_DEFLATE;
 +			ret = ARCHIVE_OK;
 +#else
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "deflate compression not supported");
 +#endif
 +		} else if (strcmp(val, "store") == 0) {
 +			zip->compression = COMPRESSION_STORE;
 +			ret = ARCHIVE_OK;
 +		}
 +	} else if (strcmp(key, "hdrcharset")  == 0) {
 +		if (val == NULL || val[0] == 0) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "%s: hdrcharset option needs a character-set name",
 +			    a->format_name);
 +		} else {
 +			zip->opt_sconv = archive_string_conversion_to_charset(
 +			    &a->archive, val, 0);
 +			if (zip->opt_sconv != NULL)
 +				ret = ARCHIVE_OK;
 +			else
 +				ret = ARCHIVE_FATAL;
 +		}
 +	} else
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "%s: unknown keyword ``%s''", a->format_name, key);
 +	return (ret);
 +}
 +
 +int
 +archive_write_set_format_zip(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct zip *zip;
 +
 +	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_write_set_format_zip");
 +
 +	/* If another format was already registered, unregister it. */
 +	if (a->format_free != NULL)
 +		(a->format_free)(a);
 +
 +	zip = (struct zip *) calloc(1, sizeof(*zip));
 +	if (zip == NULL) {
- 		archive_set_error(&a->archive, ENOMEM, "Can't allocate zip data");
++		archive_set_error(&a->archive, ENOMEM,
++		    "Can't allocate zip data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	zip->central_directory = NULL;
 +	zip->central_directory_end = NULL;
 +	zip->offset = 0;
 +	zip->written_bytes = 0;
 +	zip->remaining_data_bytes = 0;
 +
 +#ifdef HAVE_ZLIB_H
 +	zip->compression = COMPRESSION_DEFLATE;
 +	zip->len_buf = 65536;
 +	zip->buf = malloc(zip->len_buf);
 +	if (zip->buf == NULL) {
- 		archive_set_error(&a->archive, ENOMEM, "Can't allocate compression buffer");
++		archive_set_error(&a->archive, ENOMEM,
++		    "Can't allocate compression buffer");
 +		return (ARCHIVE_FATAL);
 +	}
 +#else
 +	zip->compression = COMPRESSION_STORE;
 +#endif
 +
 +	a->format_data = zip;
 +	a->format_name = "zip";
 +	a->format_options = archive_write_zip_options;
 +	a->format_write_header = archive_write_zip_header;
 +	a->format_write_data = archive_write_zip_data;
 +	a->format_finish_entry = archive_write_zip_finish_entry;
 +	a->format_close = archive_write_zip_close;
 +	a->format_free = archive_write_zip_free;
 +	a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
 +	a->archive.archive_format_name = "ZIP";
 +
 +	archive_le32enc(&zip->data_descriptor.signature,
 +	    ZIP_SIGNATURE_DATA_DESCRIPTOR);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +is_all_ascii(const char *p)
 +{
 +	const unsigned char *pp = (const unsigned char *)p;
 +
 +	while (*pp) {
 +		if (*pp++ > 127)
 +			return (0);
 +	}
 +	return (1);
 +}
 +
 +static int
 +archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 +{
 +	struct zip *zip;
 +	struct zip_local_file_header h;
 +	struct zip_extra_data_local e;
 +	struct zip_data_descriptor *d;
 +	struct zip_file_header_link *l;
 +	struct archive_string_conv *sconv;
 +	int ret, ret2 = ARCHIVE_OK;
 +	int64_t size;
 +	mode_t type;
 +
 +	/* Entries other than a regular file or a folder are skipped. */
 +	type = archive_entry_filetype(entry);
- 	if ((type != AE_IFREG) & (type != AE_IFDIR)) {
++	if (type != AE_IFREG && type != AE_IFDIR && type != AE_IFLNK) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Filetype not supported");
 +		return ARCHIVE_FAILED;
 +	}; 
 +
 +	/* Directory entries should have a size of 0. */
 +	if (type == AE_IFDIR)
 +		archive_entry_set_size(entry, 0);
 +
 +	zip = a->format_data;
 +	/* Setup default conversion. */
 +	if (zip->opt_sconv == NULL && !zip->init_default_conversion) {
 +		zip->sconv_default =
 +		    archive_string_default_conversion_for_write(&(a->archive));
 +		zip->init_default_conversion = 1;
 +	}
 +
 +	if (zip->flags == 0) {
 +		/* Initialize the general purpose flags. */
 +		zip->flags = ZIP_FLAGS;
 +		if (zip->opt_sconv != NULL) {
 +			if (strcmp(archive_string_conversion_charset_name(
 +			    zip->opt_sconv), "UTF-8") == 0)
 +				zip->flags |= ZIP_FLAGS_UTF8_NAME;
 +#if HAVE_NL_LANGINFO
 +		} else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {
 +			zip->flags |= ZIP_FLAGS_UTF8_NAME;
 +#endif
 +		}
 +	}
 +	d = &zip->data_descriptor;
 +	size = archive_entry_size(entry);
 +	zip->remaining_data_bytes = size;
 +
 +	/* Append archive entry to the central directory data. */
 +	l = (struct zip_file_header_link *) malloc(sizeof(*l));
 +	if (l == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate zip header data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	l->entry = archive_entry_clone(entry);
 +	l->flags = zip->flags;
 +	if (zip->opt_sconv != NULL)
 +		sconv = zip->opt_sconv;
 +	else
 +		sconv = zip->sconv_default;
 +	if (sconv != NULL) {
 +		const char *p;
 +		size_t len;
 +
 +		if (archive_entry_pathname_l(entry, &p, &len, 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,
 +			    "Can't translate pathname '%s' to %s",
 +			    archive_entry_pathname(entry),
 +			    archive_string_conversion_charset_name(sconv));
 +			ret2 = ARCHIVE_WARN;
 +		}
 +		if (len > 0)
 +			archive_entry_set_pathname(l->entry, p);
 +	}
 +	/* If all character of a filename is ASCII, Reset UTF-8 Name flag. */
 +	if ((l->flags & ZIP_FLAGS_UTF8_NAME) != 0 &&
 +	    is_all_ascii(archive_entry_pathname(l->entry)))
 +		l->flags &= ~ZIP_FLAGS_UTF8_NAME;
 +
 +	/* Initialize the CRC variable and potentially the local crc32(). */
 +	l->crc32 = crc32(0, NULL, 0);
- 	l->compression = zip->compression;
- 	l->compressed_size = 0;
++	if (type == AE_IFLNK) {
++		const char *p = archive_entry_symlink(l->entry);
++		if (p != NULL)
++			size = strlen(p);
++		else
++			size = 0;
++		zip->remaining_data_bytes = 0;
++		archive_entry_set_size(l->entry, size);
++		l->compression = COMPRESSION_STORE;
++		l->compressed_size = size;
++	} else {
++		l->compression = zip->compression;
++		l->compressed_size = 0;
++	}
 +	l->next = NULL;
 +	if (zip->central_directory == NULL) {
 +		zip->central_directory = l;
 +	} else {
 +		zip->central_directory_end->next = l;
 +	}
 +	zip->central_directory_end = l;
 +
- 	/* Store the offset of this header for later use in central directory. */
++	/* Store the offset of this header for later use in central
++	 * directory. */
 +	l->offset = zip->written_bytes;
 +
 +	memset(&h, 0, sizeof(h));
 +	archive_le32enc(&h.signature, ZIP_SIGNATURE_LOCAL_FILE_HEADER);
 +	archive_le16enc(&h.version, ZIP_VERSION_EXTRACT);
 +	archive_le16enc(&h.flags, l->flags);
- 	archive_le16enc(&h.compression, zip->compression);
++	archive_le16enc(&h.compression, l->compression);
 +	archive_le32enc(&h.timedate, dos_time(archive_entry_mtime(entry)));
 +	archive_le16enc(&h.filename_length, (uint16_t)path_length(l->entry));
 +
- 	switch (zip->compression) {
++	switch (l->compression) {
 +	case COMPRESSION_STORE:
- 		/* Setting compressed and uncompressed sizes even when specification says
- 		 * to set to zero when using data descriptors. Otherwise the end of the
- 		 * data for an entry is rather difficult to find. */
++		/* Setting compressed and uncompressed sizes even when
++		 * specification says to set to zero when using data
++		 * descriptors. Otherwise the end of the data for an
++		 * entry is rather difficult to find. */
 +		archive_le32enc(&h.compressed_size, size);
 +		archive_le32enc(&h.uncompressed_size, size);
 +		break;
 +#ifdef HAVE_ZLIB_H
 +	case COMPRESSION_DEFLATE:
 +		archive_le32enc(&h.uncompressed_size, size);
 +
 +		zip->stream.zalloc = Z_NULL;
 +		zip->stream.zfree = Z_NULL;
 +		zip->stream.opaque = Z_NULL;
 +		zip->stream.next_out = zip->buf;
 +		zip->stream.avail_out = zip->len_buf;
- 		if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
- 		    -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
++		if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION,
++		    Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't init deflate compressor");
 +			return (ARCHIVE_FATAL);
 +		}
 +		break;
 +#endif
 +	}
 +
 +	/* Formatting extra data. */
 +	archive_le16enc(&h.extra_length, sizeof(e));
 +	archive_le16enc(&e.time_id, ZIP_SIGNATURE_EXTRA_TIMESTAMP);
 +	archive_le16enc(&e.time_size, sizeof(e.time_flag) +
 +	    sizeof(e.mtime) + sizeof(e.atime) + sizeof(e.ctime));
 +	e.time_flag[0] = 0x07;
 +	archive_le32enc(&e.mtime, archive_entry_mtime(entry));
 +	archive_le32enc(&e.atime, archive_entry_atime(entry));
 +	archive_le32enc(&e.ctime, archive_entry_ctime(entry));
 +
 +	archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_NEW_UNIX);
 +	archive_le16enc(&e.unix_size, sizeof(e.unix_version) +
 +	    sizeof(e.unix_uid_size) + sizeof(e.unix_uid) +
 +	    sizeof(e.unix_gid_size) + sizeof(e.unix_gid));
 +	e.unix_version = 1;
 +	e.unix_uid_size = 4;
 +	archive_le32enc(&e.unix_uid, archive_entry_uid(entry));
 +	e.unix_gid_size = 4;
 +	archive_le32enc(&e.unix_gid, archive_entry_gid(entry));
 +
 +	archive_le32enc(&d->uncompressed_size, size);
 +
 +	ret = __archive_write_output(a, &h, sizeof(h));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	zip->written_bytes += sizeof(h);
 +
 +	ret = write_path(l->entry, a);
 +	if (ret <= ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	zip->written_bytes += ret;
 +
 +	ret = __archive_write_output(a, &e, sizeof(e));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	zip->written_bytes += sizeof(e);
 +
++	if (type == AE_IFLNK) {
++		const unsigned char *p;
++
++		p = (const unsigned char *)archive_entry_symlink(l->entry);
++		ret = __archive_write_output(a, p, size);
++		if (ret != ARCHIVE_OK)
++			return (ARCHIVE_FATAL);
++		zip->written_bytes += size;
++		l->crc32 = crc32(l->crc32, p, size);
++	}
++
 +	if (ret2 != ARCHIVE_OK)
 +		return (ret2);
 +	return (ARCHIVE_OK);
 +}
 +
 +static ssize_t
 +archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
 +{
 +	int ret;
 +	struct zip *zip = a->format_data;
 +	struct zip_file_header_link *l = zip->central_directory_end;
 +
 +	if ((int64_t)s > zip->remaining_data_bytes)
 +		s = (size_t)zip->remaining_data_bytes;
 +
 +	if (s == 0) return 0;
 +
- 	switch (zip->compression) {
++	switch (l->compression) {
 +	case COMPRESSION_STORE:
 +		ret = __archive_write_output(a, buff, s);
 +		if (ret != ARCHIVE_OK) return (ret);
 +		zip->written_bytes += s;
 +		zip->remaining_data_bytes -= s;
 +		l->compressed_size += s;
 +		l->crc32 = crc32(l->crc32, buff, s);
 +		return (s);
 +#if HAVE_ZLIB_H
 +	case COMPRESSION_DEFLATE:
 +		zip->stream.next_in = (unsigned char*)(uintptr_t)buff;
 +		zip->stream.avail_in = s;
 +		do {
 +			ret = deflate(&zip->stream, Z_NO_FLUSH);
 +			if (ret == Z_STREAM_ERROR)
 +				return (ARCHIVE_FATAL);
 +			if (zip->stream.avail_out == 0) {
- 				ret = __archive_write_output(a, zip->buf, zip->len_buf);
++				ret = __archive_write_output(a, zip->buf,
++					zip->len_buf);
 +				if (ret != ARCHIVE_OK)
 +					return (ret);
 +				l->compressed_size += zip->len_buf;
 +				zip->written_bytes += zip->len_buf;
 +				zip->stream.next_out = zip->buf;
 +				zip->stream.avail_out = zip->len_buf;
 +			}
 +		} while (zip->stream.avail_in != 0);
 +		zip->remaining_data_bytes -= s;
 +		/* If we have it, use zlib's fast crc32() */
 +		l->crc32 = crc32(l->crc32, buff, s);
 +		return (s);
 +#endif
 +
 +	default:
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid ZIP compression type");
 +		return ARCHIVE_FATAL;
 +	}
 +}
 +
 +static int
 +archive_write_zip_finish_entry(struct archive_write *a)
 +{
 +	/* Write the data descripter after file data has been written. */
 +	int ret;
 +	struct zip *zip = a->format_data;
 +	struct zip_data_descriptor *d = &zip->data_descriptor;
 +	struct zip_file_header_link *l = zip->central_directory_end;
 +#if HAVE_ZLIB_H
 +	size_t reminder;
 +#endif
 +
- 	switch(zip->compression) {
++	switch(l->compression) {
 +	case COMPRESSION_STORE:
 +		break;
 +#if HAVE_ZLIB_H
 +	case COMPRESSION_DEFLATE:
 +		for (;;) {
 +			ret = deflate(&zip->stream, Z_FINISH);
 +			if (ret == Z_STREAM_ERROR)
 +				return (ARCHIVE_FATAL);
 +			reminder = zip->len_buf - zip->stream.avail_out;
 +			ret = __archive_write_output(a, zip->buf, reminder);
 +			if (ret != ARCHIVE_OK)
 +				return (ret);
 +			l->compressed_size += reminder;
 +			zip->written_bytes += reminder;
 +			zip->stream.next_out = zip->buf;
 +			if (zip->stream.avail_out != 0)
 +				break;
 +			zip->stream.avail_out = zip->len_buf;
 +		}
 +		deflateEnd(&zip->stream);
 +		break;
 +#endif
 +	}
 +
 +	archive_le32enc(&d->crc32, l->crc32);
 +	archive_le32enc(&d->compressed_size, l->compressed_size);
 +	ret = __archive_write_output(a, d, sizeof(*d));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	zip->written_bytes += sizeof(*d);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_write_zip_close(struct archive_write *a)
 +{
 +	struct zip *zip;
 +	struct zip_file_header_link *l;
 +	struct zip_file_header h;
 +	struct zip_central_directory_end end;
 +	struct zip_extra_data_central e;
 +	int64_t offset_start, offset_end;
 +	int entries;
 +	int ret;
 +
 +	zip = a->format_data;
 +	l = zip->central_directory;
 +
 +	/*
- 	 * Formatting central directory file header fields that are fixed for all entries.
++	 * Formatting central directory file header fields that are
++	 * fixed for all entries.
 +	 * Fields not used (and therefor 0) are:
 +	 *
 +	 *   - comment_length
 +	 *   - disk_number
 +	 *   - attributes_internal
 +	 */
 +	memset(&h, 0, sizeof(h));
 +	archive_le32enc(&h.signature, ZIP_SIGNATURE_FILE_HEADER);
 +	archive_le16enc(&h.version_by, ZIP_VERSION_BY);
 +	archive_le16enc(&h.version_extract, ZIP_VERSION_EXTRACT);
 +
 +	entries = 0;
 +	offset_start = zip->written_bytes;
 +
 +	/* Formatting individual header fields per entry and
 +	 * writing each entry. */
 +	while (l != NULL) {
 +		archive_le16enc(&h.flags, l->flags);
 +		archive_le16enc(&h.compression, l->compression);
- 		archive_le32enc(&h.timedate, dos_time(archive_entry_mtime(l->entry)));
++		archive_le32enc(&h.timedate,
++			dos_time(archive_entry_mtime(l->entry)));
 +		archive_le32enc(&h.crc32, l->crc32);
 +		archive_le32enc(&h.compressed_size, l->compressed_size);
- 		archive_le32enc(&h.uncompressed_size, archive_entry_size(l->entry));
- 		archive_le16enc(&h.filename_length, (uint16_t)path_length(l->entry));
++		archive_le32enc(&h.uncompressed_size,
++			archive_entry_size(l->entry));
++		archive_le16enc(&h.filename_length,
++			(uint16_t)path_length(l->entry));
 +		archive_le16enc(&h.extra_length, sizeof(e));
- 		archive_le16enc(&h.attributes_external[2], archive_entry_mode(l->entry));
++		archive_le16enc(&h.attributes_external[2],
++			archive_entry_mode(l->entry));
 +		archive_le32enc(&h.offset, l->offset);
 +
 +		/* Formatting extra data. */
 +		archive_le16enc(&e.time_id, ZIP_SIGNATURE_EXTRA_TIMESTAMP);
- 		archive_le16enc(&e.time_size, sizeof(e.mtime) + sizeof(e.time_flag));
++		archive_le16enc(&e.time_size,
++			sizeof(e.mtime) + sizeof(e.time_flag));
 +		e.time_flag[0] = 0x07;
 +		archive_le32enc(&e.mtime, archive_entry_mtime(l->entry));
 +		archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_NEW_UNIX);
 +		archive_le16enc(&e.unix_size, 0x0000);
 +
 +		ret = __archive_write_output(a, &h, sizeof(h));
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		zip->written_bytes += sizeof(h);
 +
 +		ret = write_path(l->entry, a);
 +		if (ret <= ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		zip->written_bytes += ret;
 +
 +		ret = __archive_write_output(a, &e, sizeof(e));
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		zip->written_bytes += sizeof(e);
 +
 +		l = l->next;
 +		entries++;
 +	}
 +	offset_end = zip->written_bytes;
 +
 +	/* Formatting end of central directory. */
 +	memset(&end, 0, sizeof(end));
 +	archive_le32enc(&end.signature, ZIP_SIGNATURE_CENTRAL_DIRECTORY_END);
 +	archive_le16enc(&end.entries_disk, entries);
 +	archive_le16enc(&end.entries, entries);
 +	archive_le32enc(&end.size, offset_end - offset_start);
 +	archive_le32enc(&end.offset, offset_start);
 +
 +	/* Writing end of central directory. */
 +	ret = __archive_write_output(a, &end, sizeof(end));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	zip->written_bytes += sizeof(end);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_write_zip_free(struct archive_write *a)
 +{
 +	struct zip *zip;
 +	struct zip_file_header_link *l;
 +
 +	zip = a->format_data;
 +	while (zip->central_directory != NULL) {
 +	   l = zip->central_directory;
 +	   zip->central_directory = l->next;
 +	   archive_entry_free(l->entry);
 +	   free(l);
 +	}
 +#ifdef HAVE_ZLIB_H
 +	free(zip->buf);
 +#endif
 +	free(zip);
 +	a->format_data = NULL;
 +	return (ARCHIVE_OK);
 +}
 +
 +/* Convert into MSDOS-style date/time. */
 +static unsigned int
 +dos_time(const time_t unix_time)
 +{
 +	struct tm *t;
 +	unsigned int dt;
 +
 +	/* This will not preserve time when creating/extracting the archive
 +	 * on two systems with different time zones. */
 +	t = localtime(&unix_time);
 +
 +	/* MSDOS-style date/time is only between 1980-01-01 and 2107-12-31 */
 +	if (t->tm_year < 1980 - 1900)
 +		/* Set minimum date/time '1980-01-01 00:00:00'. */
 +		dt = 0x00210000U;
 +	else if (t->tm_year > 2107 - 1900)
 +		/* Set maximum date/time '2107-12-31 23:59:58'. */
 +		dt = 0xff9fbf7dU;
 +	else {
 +		dt = 0;
 +		dt += ((t->tm_year - 80) & 0x7f) << 9;
 +		dt += ((t->tm_mon + 1) & 0x0f) << 5;
 +		dt += (t->tm_mday & 0x1f);
 +		dt <<= 16;
 +		dt += (t->tm_hour & 0x1f) << 11;
 +		dt += (t->tm_min & 0x3f) << 5;
 +		dt += (t->tm_sec & 0x3e) >> 1; /* Only counting every 2 seconds. */
 +	}
 +	return dt;
 +}
 +
 +static size_t
 +path_length(struct archive_entry *entry)
 +{
 +	mode_t type;
 +	const char *path;
 +
 +	type = archive_entry_filetype(entry);
 +	path = archive_entry_pathname(entry);
 +
 +	if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {
 +		return strlen(path) + 1;
 +	} else {
 +		return strlen(path);
 +	}
 +}
 +
 +static int
 +write_path(struct archive_entry *entry, struct archive_write *archive)
 +{
 +	int ret;
 +	const char *path;
 +	mode_t type;
 +	size_t written_bytes;
 +
 +	path = archive_entry_pathname(entry);
 +	type = archive_entry_filetype(entry);
 +	written_bytes = 0;
 +
 +	ret = __archive_write_output(archive, path, strlen(path));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	written_bytes += strlen(path);
 +
 +	/* Folders are recognized by a traling slash. */
 +	if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {
 +		ret = __archive_write_output(archive, "/", 1);
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		written_bytes += 1;
 +	}
 +
 +	return ((int)written_bytes);
 +}

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fd42bf1bdcb95615dd725ae588db02b22a3aebaa
commit fd42bf1bdcb95615dd725ae588db02b22a3aebaa
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jan 5 09:02:01 2012 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 5 09:02:01 2012 -0500

    libarchive: Set .gitattributes to allow trailing whitespace
    
    We do not care about trailing whitespace in third-party code.

diff --git a/Utilities/cmlibarchive/.gitattributes b/Utilities/cmlibarchive/.gitattributes
index 2885cc6..be7062b 100644
--- a/Utilities/cmlibarchive/.gitattributes
+++ b/Utilities/cmlibarchive/.gitattributes
@@ -1,2 +1,2 @@
-*.h              whitespace=indent-with-non-tab
-*.c              whitespace=indent-with-non-tab
+*.h              whitespace=indent-with-non-tab,-blank-at-eol
+*.c              whitespace=indent-with-non-tab,-blank-at-eol

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4f4fe6e50bb3dbe59f9bc3cc848cbd07dead324d
commit 4f4fe6e50bb3dbe59f9bc3cc848cbd07dead324d
Author:     LibArchive Upstream <libarchive-discuss at googlegroups.com>
AuthorDate: Sat Dec 31 13:54:34 2011 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 5 08:52:42 2012 -0500

    libarchive 3.0.2-r4051 (reduced)
    
    Extract upstream libarchive using the following shell code.
    
    url=https://libarchive.googlecode.com/svn/release/3.0
    v=3.0.2
    r=4051
    paths="
      CMakeLists.txt
      COPYING
      CTestConfig.cmake
      build/cmake
      build/pkgconfig
      build/utils
      build/version
      libarchive/*.*
    "
    date=$(svn log -q -c$r $url |
           sed -n "/^r/ {s/[^|]*|[^|]*|//;p;}")
    svn export -r$r $url libarchive-$v-r$r &&
    mkdir libarchive-$v-r$r-reduced &&
    (cd libarchive-$v-r$r && tar c $paths) |
    (cd libarchive-$v-r$r-reduced && tar x)
    echo "r$r date: $date"

diff --git a/CMakeLists.txt b/CMakeLists.txt
index aed3c0a..60672ce 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,12 +2,12 @@
 #
 PROJECT(libarchive C)
 #
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3 FATAL_ERROR)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
 SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")
 if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
   set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${libarchive_BINARY_DIR}/bin)
 endif()
-SET(CMAKE_BUILD_TYPE "Debug")
+SET(CMAKE_BUILD_TYPE "Release")
 
 # On MacOS, prefer MacPorts libraries to system libraries.
 # I haven't come up with a compelling argument for this to be conditional.
@@ -38,9 +38,10 @@ SET(LIBARCHIVE_VERSION_STRING  "${VERSION}")
 # INTERFACE_VERSION increments with every release
 # libarchive 2.7 == interface version 9 = 2 + 7 
 # libarchive 2.8 == interface version 10 = 2 + 8
-# libarchive 3.0 == interface version 11
-# libarchive 3.x == interface version 11 + x
-math(EXPR INTERFACE_VERSION  "11 + ${_minor}")
+# libarchive 2.9 == interface version 11 = 2 + 9
+# libarchive 3.0 == interface version 12
+# libarchive 3.x == interface version 12 + x
+math(EXPR INTERFACE_VERSION  "12 + ${_minor}")
 
 # Set SOVERSION == Interface version
 # ?? Should there be more here ??
@@ -50,17 +51,13 @@ SET(SOVERSION "${INTERFACE_VERSION}")
 # aggressive about diagnosing build problems; this can get
 # relaxed somewhat in final shipping versions.
 IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
-  ADD_DEFINITIONS(-Wall -Werror)
-  SET(CMAKE_REQUIRED_FLAGS "-Wall -Werror")
+  ADD_DEFINITIONS(-Wall)
+  SET(CMAKE_REQUIRED_FLAGS "-Wall")
 ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
 
 # Enable CTest/CDash support
 include(CTest)
 
-# Provide ADD_TEST_28 macro to approximate CMake 2.8 ADD_TEST(NAME).
-# TODO: Require CMake 2.8 and drop this workaround (perhaps late 2010).
-INCLUDE(AddTest28)
-
 OPTION(ENABLE_NETTLE "Enable use of Nettle" ON)
 OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON)
 OPTION(ENABLE_TAR "Enable tar building" ON)
diff --git a/build/cmake/AddTest28.cmake b/build/cmake/AddTest28.cmake
deleted file mode 100644
index ab26a9a..0000000
--- a/build/cmake/AddTest28.cmake
+++ /dev/null
@@ -1,107 +0,0 @@
-# - Macro approximating the CMake 2.8 ADD_TEST(NAME) signature.
-# ADD_TEST_28(NAME <name> COMMAND <command> [arg1 [arg2 ...]])
-#  <name>    - The name of the test
-#  <command> - The test executable
-#  [argN...] - Arguments to the test executable
-# This macro approximates the ADD_TEST(NAME) signature provided in
-# CMake 2.8 but works with CMake 2.6 too.  See CMake 2.8 documentation
-# of ADD_TEST()for details.
-#
-# This macro automatically replaces a <command> that names an
-# executable target with the target location.  A generator expression
-# of the form "$<TARGET_FILE:tgt>" is supported in both the command
-# and arguments of the test.  Howerver, this macro only works for
-# targets without per-config output name properties set.
-#
-# Example usage:
-#   add_test(NAME mytest COMMAND testDriver --exe $<TARGET_FILE:myexe>)
-# This creates a test "mytest" whose command runs a testDriver tool
-# passing the full path to the executable file produced by target
-# "myexe".
-
-#=============================================================================
-# Copyright 2009 Kitware, Inc.
-# 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.
-#=============================================================================
-
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3)
-
-# CMake 2.8 supports ADD_TEST(NAME) natively.
-IF(NOT "${CMAKE_VERSION}" VERSION_LESS "2.8")
-  MACRO(ADD_TEST_28)
-    ADD_TEST(${ARGV})
-  ENDMACRO()
-  RETURN()
-ENDIF()
-
-# Simulate ADD_TEST(NAME) signature from CMake 2.8.
-MACRO(ADD_TEST_28 NAME name COMMAND command)
-  # Enforce the signature.
-  IF(NOT "x${NAME}" STREQUAL "xNAME")
-    MESSAGE(FATAL_ERROR "First ADD_TEST_28 argument must be \"NAME\"")
-  ENDIF()
-  IF(NOT "x${COMMAND}" STREQUAL "xCOMMAND")
-    MESSAGE(FATAL_ERROR "Third ADD_TEST_28 argument must be \"COMMAND\"")
-  ENDIF()
-
-  # Perform "COMMAND myexe ..." substitution.
-  SET(cmd "${command}")
-  IF(TARGET "${cmd}")
-    _ADD_TEST_28_GET_EXE(${cmd} cmd)
-  ENDIF()
-
-  # Perform "COMMAND ... $<TARGET_FILE:myexe> ..." substitution.
-  SET(target_file "\\$<TARGET_FILE:(.+)>")
-  SET(args)
-  FOREACH(ARG ${cmd} ${ARGN})
-    SET(arg "${ARG}")
-    IF("${arg}" MATCHES "${target_file}")
-      STRING(REGEX REPLACE "${target_file}" "\\1" tgt "${arg}")
-      IF(TARGET "${tgt}")
-        _ADD_TEST_28_GET_EXE(${tgt} exe)
-        STRING(REGEX REPLACE "${target_file}" "${exe}" arg "${arg}")
-      ENDIF()
-    ENDIF()
-    LIST(APPEND args "${arg}")
-  ENDFOREACH()
-
-  # Invoke old ADD_TEST() signature with transformed arguments.
-  ADD_TEST(${name} ${args})
-ENDMACRO()
-
-# Get the test-time location of an executable target.
-MACRO(_ADD_TEST_28_GET_EXE tgt exe_var)
-  # The LOCATION property gives a build-time location.
-  GET_TARGET_PROPERTY(${exe_var} ${tgt} LOCATION)
-
-  # In single-configuration generatrs the build-time and test-time
-  # locations are the same because there is no per-config variable
-  # reference.  In multi-configuration generators the following
-  # substitution converts the build-time configuration variable
-  # reference to a test-time configuration variable reference.
-  IF(CMAKE_CONFIGURATION_TYPES)
-    STRING(REPLACE "${CMAKE_CFG_INTDIR}" "\${CTEST_CONFIGURATION_TYPE}"
-      ${exe_var} "${${exe_var}}")
-  ENDIF(CMAKE_CONFIGURATION_TYPES)
-ENDMACRO()
diff --git a/build/version b/build/version
index 6ff875b..ee575c8 100644
--- a/build/version
+++ b/build/version
@@ -1 +1 @@
-3000001b
+3000002
diff --git a/libarchive/archive.h b/libarchive/archive.h
index 14c2aed..13cbe79 100644
--- a/libarchive/archive.h
+++ b/libarchive/archive.h
@@ -124,27 +124,16 @@ extern "C" {
  * easy to compare versions at build time: for version a.b.c, the
  * version number is printf("%d%03d%03d",a,b,c).  For example, if you
  * know your application requires version 2.12.108 or later, you can
- * assert that ARCHIVE_VERSION >= 2012108.
- *
- * This single-number format was introduced with libarchive 1.9.0 in
- * the libarchive 1.x family and libarchive 2.2.4 in the libarchive
- * 2.x family.  The following may be useful if you really want to do
- * feature detection for earlier libarchive versions (which defined
- * ARCHIVE_API_VERSION and ARCHIVE_API_FEATURE instead):
- *
- * #ifndef ARCHIVE_VERSION_NUMBER
- * #define ARCHIVE_VERSION_NUMBER	\
- *             (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
- * #endif
+ * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define	ARCHIVE_VERSION_NUMBER 3000001
+#define	ARCHIVE_VERSION_NUMBER 3000002
 __LA_DECL int		archive_version_number(void);
 
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define	ARCHIVE_VERSION_STRING "libarchive 3.0.1b"
+#define	ARCHIVE_VERSION_STRING "libarchive 3.0.2"
 __LA_DECL const char *	archive_version_string(void);
 
 /* Declare our basic types. */
@@ -447,8 +436,6 @@ __LA_DECL int archive_read_data_block(struct archive *a,
  *  'into_fd': writes data to specified filedes
  */
 __LA_DECL int archive_read_data_skip(struct archive *);
-__LA_DECL int archive_read_data_into_buffer(struct archive *,
-			    void *buffer, __LA_SSIZE_T len);
 __LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
 
 /*
diff --git a/libarchive/archive_entry.3 b/libarchive/archive_entry.3
index 1bd7cfb..10e3c34 100644
--- a/libarchive/archive_entry.3
+++ b/libarchive/archive_entry.3
@@ -26,7 +26,7 @@
 .\" $FreeBSD: src/lib/libarchive/archive_entry.3,v 1.18 2008/05/26 17:00:22 kientzle Exp $
 .\"
 .Dd Feburary 22, 2010
-.Dt archive_entry 3
+.Dt ARCHIVE_ENTRY 3
 .Os
 .Sh NAME
 .Nm archive_entry_clear ,
diff --git a/libarchive/archive_entry.h b/libarchive/archive_entry.h
index fcd7657..533dc7f 100644
--- a/libarchive/archive_entry.h
+++ b/libarchive/archive_entry.h
@@ -29,7 +29,7 @@
 #define	ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define	ARCHIVE_VERSION_NUMBER 3000001
+#define	ARCHIVE_VERSION_NUMBER 3000002
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
diff --git a/libarchive/archive_entry_acl.3 b/libarchive/archive_entry_acl.3
index 896b35a..93906e7 100644
--- a/libarchive/archive_entry_acl.3
+++ b/libarchive/archive_entry_acl.3
@@ -23,7 +23,7 @@
 .\" SUCH DAMAGE.
 .\"
 .Dd February 21, 2010
-.Dt archive_entry_acl 3
+.Dt ARCHIVE_ENTRY_ACL 3
 .Os
 .Sh NAME
 .Nm archive_entry_acl_add_entry ,
diff --git a/libarchive/archive_entry_linkify.3 b/libarchive/archive_entry_linkify.3
index 6b1b9a5..a34b095 100644
--- a/libarchive/archive_entry_linkify.3
+++ b/libarchive/archive_entry_linkify.3
@@ -23,7 +23,7 @@
 .\" SUCH DAMAGE.
 .\"
 .Dd February 20, 2010
-.Dt archive_entry_linkify 3
+.Dt ARCHIVE_ENTRY_LINKIFY 3
 .Os
 .Sh NAME
 .Nm archive_entry_linkresolver ,
diff --git a/libarchive/archive_entry_paths.3 b/libarchive/archive_entry_paths.3
index 05243c0..621f655 100644
--- a/libarchive/archive_entry_paths.3
+++ b/libarchive/archive_entry_paths.3
@@ -23,7 +23,7 @@
 .\" SUCH DAMAGE.
 .\"
 .Dd February 22, 2010
-.Dt archive_entry_paths 3
+.Dt ARCHIVE_ENTRY_PATHS 3
 .Os
 .Sh NAME
 .Nm archive_entry_hardlink ,
diff --git a/libarchive/archive_entry_perms.3 b/libarchive/archive_entry_perms.3
index 452a19f..164af97 100644
--- a/libarchive/archive_entry_perms.3
+++ b/libarchive/archive_entry_perms.3
@@ -24,7 +24,7 @@
 .\" SUCH DAMAGE.
 .\"
 .Dd February 22, 2010
-.Dt archive_entry_perms 3
+.Dt ARCHIVE_ENTRY_PERMS 3
 .Os
 .Sh NAME
 .Nm archive_entry_gid ,
diff --git a/libarchive/archive_entry_stat.3 b/libarchive/archive_entry_stat.3
index a988ecf..36a7efb 100644
--- a/libarchive/archive_entry_stat.3
+++ b/libarchive/archive_entry_stat.3
@@ -23,7 +23,7 @@
 .\" SUCH DAMAGE.
 .\"
 .Dd May 12, 2008
-.Dt archive_entry 3
+.Dt ARCHIVE_ENTRY 3
 .Os
 .Sh NAME
 .Nm archive_entry_stat ,
diff --git a/libarchive/archive_entry_time.3 b/libarchive/archive_entry_time.3
index 7787ca5..85a8209 100644
--- a/libarchive/archive_entry_time.3
+++ b/libarchive/archive_entry_time.3
@@ -26,7 +26,7 @@
 .\" $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
+.Dt ARCHIVE_ENTRY_TIME 3
 .Os
 .Sh NAME
 .Nm archive_entry_atime ,
diff --git a/libarchive/archive_read.3 b/libarchive/archive_read.3
index 70527fb..5285192 100644
--- a/libarchive/archive_read.3
+++ b/libarchive/archive_read.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
 .\"
 .Dd March 23, 2011
-.Dt archive_read 3
+.Dt ARCHIVE_READ 3
 .Os
 .Sh NAME
 .Nm archive_read
diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c
index 441be53..b1d4914 100644
--- a/libarchive/archive_read.c
+++ b/libarchive/archive_read.c
@@ -668,22 +668,6 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
 	return (bytes_read);
 }
 
-#if ARCHIVE_API_VERSION < 3
-/*
- * Obsolete function provided for compatibility only.  Note that the API
- * of this function doesn't allow the caller to detect if the remaining
- * data from the archive entry is shorter than the buffer provided, or
- * even if an error occurred while reading data.
- */
-int
-archive_read_data_into_buffer(struct archive *a, void *d, ssize_t len)
-{
-
-	archive_read_data(a, d, len);
-	return (ARCHIVE_OK);
-}
-#endif
-
 /*
  * Skip over all remaining data in this entry.
  */
diff --git a/libarchive/archive_read_data.3 b/libarchive/archive_read_data.3
index a5898e7..78d0497 100644
--- a/libarchive/archive_read_data.3
+++ b/libarchive/archive_read_data.3
@@ -25,15 +25,12 @@
 .\" $FreeBSD$
 .\"
 .Dd March 22, 2011
-.Dt archive_read_data 3
+.Dt ARCHIVE_READ_DATA 3
 .Os
 .Sh NAME
 .Nm archive_read_data
 .Nm archive_read_data_block ,
 .Nm archive_read_data_skip ,
-.\" #if ARCHIVE_API_VERSION < 3
-.Nm archive_read_data_into_buffer ,
-.\" #endif
 .Nm archive_read_data_into_fd
 .Nd functions for reading streaming archives
 .Sh SYNOPSIS
@@ -49,10 +46,6 @@
 .Fc
 .Ft int
 .Fn archive_read_data_skip "struct archive *"
-.\" #if ARCHIVE_API_VERSION < 3
-.Ft int
-.Fn archive_read_data_into_buffer "struct archive *" "void *" "ssize_t len"
-.\" #endif
 .Ft int
 .Fn archive_read_data_into_fd "struct archive *" "int fd"
 .\"
@@ -84,13 +77,6 @@ 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.
-.\" #if ARCHIVE_API_VERSION < 3
-.It Fn archive_read_data_into_buffer
-This function is deprecated and will be removed.
-Use
-.Fn archive_read_data
-instead.
-.\" #endif
 .It Fn archive_read_data_into_fd
 A convenience function that repeatedly calls
 .Fn archive_read_data_block
diff --git a/libarchive/archive_read_data_into_fd.c b/libarchive/archive_read_data_into_fd.c
index 04d3ab0..14f9410 100644
--- a/libarchive/archive_read_data_into_fd.c
+++ b/libarchive/archive_read_data_into_fd.c
@@ -45,7 +45,7 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_data_into_fd.c,v 1.16 2008/0
 /*
  * This implementation minimizes copying of data and is sparse-file aware.
  */
-int
+static int
 pad_to(struct archive *a, int fd, int can_lseek,
     size_t nulls_size, const char *nulls,
     int64_t target_offset, int64_t actual_offset)
diff --git a/libarchive/archive_read_disk.3 b/libarchive/archive_read_disk.3
index d3b6101..3c49bff 100644
--- a/libarchive/archive_read_disk.3
+++ b/libarchive/archive_read_disk.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_read_disk.3 190957 2009-04-12 05:04:02Z kientzle $
 .\"
 .Dd March 10, 2009
-.Dt archive_read_disk 3
+.Dt ARCHIVE_READ_DISK 3
 .Os
 .Sh NAME
 .Nm archive_read_disk_new ,
@@ -283,7 +283,7 @@ and first appeared in
 The
 .Nm libarchive
 library was written by
-.An Tim Kientzle Aq kientzle at freebsd.org .
+.An Tim Kientzle Aq kientzle at FreeBSD.org .
 .Sh BUGS
 The
 .Dq standard
diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c
index cc39151..8ce88b3 100644
--- a/libarchive/archive_read_disk_entry_from_file.c
+++ b/libarchive/archive_read_disk_entry_from_file.c
@@ -246,7 +246,7 @@ archive_read_disk_entry_from_file(struct archive *_a,
 	return (r);
 }
 
-#ifdef __APPLE__
+#if defined(__APPLE__) && defined(HAVE_COPYFILE_H)
 /*
  * The Mac OS "copyfile()" API copies the extended metadata for a
  * file into a separate file in AppleDouble format (see RFC 1740).
diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c
index 7a9c3d8..b81ab30 100644
--- a/libarchive/archive_read_disk_posix.c
+++ b/libarchive/archive_read_disk_posix.c
@@ -1321,9 +1321,11 @@ setup_current_filesystem(struct archive_read_disk *a)
 		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)
diff --git a/libarchive/archive_read_extract.3 b/libarchive/archive_read_extract.3
index 950248e..882c6e1 100644
--- a/libarchive/archive_read_extract.3
+++ b/libarchive/archive_read_extract.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd March 22, 2011
-.Dt archive_read_extract 3
+.Dt ARCHIVE_READ_EXTRACT 3
 .Os
 .Sh NAME
 .Nm archive_read_extract ,
diff --git a/libarchive/archive_read_filter.3 b/libarchive/archive_read_filter.3
index 7b506cc..1cfa215 100644
--- a/libarchive/archive_read_filter.3
+++ b/libarchive/archive_read_filter.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd March 19, 2011
-.Dt archive_read_filter 3
+.Dt ARCHIVE_READ_FILTER 3
 .Os
 .Sh NAME
 .Nm archive_read_support_filter_all ,
diff --git a/libarchive/archive_read_format.3 b/libarchive/archive_read_format.3
index 3b5abf3..e707e05 100644
--- a/libarchive/archive_read_format.3
+++ b/libarchive/archive_read_format.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
 .\"
 .Dd March 19, 2011
-.Dt archive_read_format 3
+.Dt ARCHIVE_READ_FORMAT 3
 .Os
 .Sh NAME
 .Nm archive_read_support_format_7zip ,
diff --git a/libarchive/archive_read_free.3 b/libarchive/archive_read_free.3
index 5838e20..f5f2515 100644
--- a/libarchive/archive_read_free.3
+++ b/libarchive/archive_read_free.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
 .\"
 .Dd March 20, 2011
-.Dt archive_read_free 3
+.Dt ARCHIVE_READ_FREE 3
 .Os
 .Sh NAME
 .Nm archive_read_close ,
diff --git a/libarchive/archive_read_header.3 b/libarchive/archive_read_header.3
index f8543f7..999e963 100644
--- a/libarchive/archive_read_header.3
+++ b/libarchive/archive_read_header.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd March 22, 2011
-.Dt archive_read_header 3
+.Dt ARCHIVE_READ_HEADER 3
 .Os
 .Sh NAME
 .Nm archive_read_next_header ,
diff --git a/libarchive/archive_read_new.3 b/libarchive/archive_read_new.3
index d2d9862..e04406a 100644
--- a/libarchive/archive_read_new.3
+++ b/libarchive/archive_read_new.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
 .\"
 .Dd March 20, 2011
-.Dt archive_read_new 3
+.Dt ARCHIVE_READ_NEW 3
 .Os
 .Sh NAME
 .Nm archive_read_new
diff --git a/libarchive/archive_read_open.3 b/libarchive/archive_read_open.3
index ff15641..09c0575 100644
--- a/libarchive/archive_read_open.3
+++ b/libarchive/archive_read_open.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
 .\"
 .Dd March 19, 2011
-.Dt archive_read_open 3
+.Dt ARCHIVE_READ_OPEN 3
 .Os
 .Sh NAME
 .Nm archive_read_open ,
diff --git a/libarchive/archive_read_set_options.3 b/libarchive/archive_read_set_options.3
index 2079d2e..81efb08 100644
--- a/libarchive/archive_read_set_options.3
+++ b/libarchive/archive_read_set_options.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd April 13, 2009
-.Dt archive_read_options 3
+.Dt ARCHIVE_READ_OPTIONS 3
 .Os
 .Sh NAME
 .Nm archive_read_set_filter_option ,
diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c
index f581ee5..330ba6a 100644
--- a/libarchive/archive_read_support_format_7zip.c
+++ b/libarchive/archive_read_support_format_7zip.c
@@ -204,6 +204,10 @@ 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;
@@ -228,6 +232,7 @@ struct _7zip {
 	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;
@@ -288,6 +293,10 @@ struct _7zip {
 	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;
@@ -324,12 +333,11 @@ 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 ssize_t	decode_header_image(struct archive_read *, struct _7zip *,
-		    struct _7z_stream_info *, const unsigned char *, uint64_t,
-		    const void **);
+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 *);
+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 *);
@@ -341,39 +349,39 @@ 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, 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(const unsigned char *, size_t, uint64_t *);
-static int	read_Bools(unsigned char *, size_t, const unsigned char *,
-		    size_t);
-static int	read_CodersInfo(struct _7z_coders_info *,
-		    const unsigned char *, size_t);
-static int	read_Digests(struct _7z_digests *, size_t,
-		    const unsigned char *, size_t);
-static int	read_Folder(struct _7z_folder *, const unsigned char *,
-		    size_t);
-static int	read_Header(struct _7zip *, struct _7z_header_info *,
-		    const unsigned char *, size_t);
-static int	read_PackInfo(struct _7z_pack_info *, const unsigned char *,
+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_StreamsInfo(struct _7zip *, struct _7z_stream_info *,
-		    const unsigned char *, size_t);
-static int	read_SubStreamsInfo(struct _7z_substream_info *,
-		    struct _7z_folder *, size_t, const unsigned char *,
-		    size_t);
-static int	read_Times(struct _7zip *, struct _7z_header_info *, int,
-		    const unsigned char *, 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);
+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 size_t	x86_Convert(uint8_t *, size_t, uint32_t, uint32_t *);
-ssize_t		Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
+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
@@ -641,16 +649,16 @@ archive_read_format_7zip_read_header(struct archive_read *a,
 		int r;
 
 		/*
-		 * Symbolic-name is recorded as its contents. We have to read the
-		 * contents at this time.
+		 * 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);
+			r = archive_read_format_7zip_read_data(a, &buff,
+				&size, &offset);
 			if (r < ARCHIVE_WARN)
 				return (r);
 			symname = realloc(symname, symsize + size + 1);
@@ -663,13 +671,15 @@ archive_read_format_7zip_read_header(struct archive_read *a,
 			symsize += size;
 		}
 		if (symsize == 0) {
-			/* If there is no synname, handle it as a regular file. */
+			/* 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);
+			archive_entry_copy_symlink(entry,
+			    (const char *)symname);
 			free(symname);
 		}
 		archive_entry_set_size(entry, 0);
@@ -706,7 +716,7 @@ archive_read_format_7zip_read_data(struct archive_read *a,
 		return (ARCHIVE_EOF);
 	}
 
-	bytes = read_stream(a, buff, zip->entry_bytes_remaining);
+	bytes = read_stream(a, buff, zip->entry_bytes_remaining, 0);
 	if (bytes < 0)
 		return ((int)bytes);
 	if (bytes == 0) {
@@ -929,6 +939,8 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
 			}
 			zip->codec2 = coder2->codec;
 			zip->bcj_state = 0;
+			if (coder2->codec == _7Z_X86)
+				x86_Init(zip);
 		}
 		break;
 	default:
@@ -990,7 +1002,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
 					fi++;
 				} else
 					/* Use our filter. */
-					zip->bcj_state = 0;
+					x86_Init(zip);
 				break;
 			case _7Z_X86_BCJ2:
 				/* Use our filter. */
@@ -1213,6 +1225,14 @@ decompress(struct archive_read *a, struct _7zip *zip,
 
 	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--;
@@ -1233,7 +1253,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
 		/*
 		 * Decord a remaining decompressed main stream for BCJ2.
 		 */
-		if (zip->tmp_stream_bytes_remaining > 0) {
+		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);
@@ -1249,7 +1269,8 @@ decompress(struct archive_read *a, struct _7zip *zip,
 			if (o_avail_in == 0 || t_avail_out == 0) {
 				*used = 0;
 				*outbytes = o_avail_out - t_avail_out;
-				if (o_avail_in == 0)
+				if (o_avail_in == 0 &&
+				    zip->tmp_stream_bytes_remaining)
 					ret = ARCHIVE_EOF;
 				return (ret);
 			}
@@ -1440,7 +1461,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
 	 * Decord BCJ.
 	 */
 	if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) {
-		size_t l = x86_Convert(buff, *outbytes, 0, &(zip->bcj_state));
+		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) {
@@ -1520,49 +1541,48 @@ free_decompression(struct archive_read *a, struct _7zip *zip)
 }
 
 static int
-parse_7zip_uint64(const unsigned char *p, size_t len, uint64_t *val)
+parse_7zip_uint64(struct archive_read *a, uint64_t *val)
 {
-	const unsigned char *_p = p;
+	const unsigned char *p;
 	unsigned char avail, mask;
 	int i;
 
-	if (len-- == 0)
+	if ((p = header_bytes(a, 1)) == NULL)
 		return (-1);
-	avail = *p++;
+	avail = *p;
 	mask = 0x80;
 	*val = 0;
 	for (i = 0; i < 8; i++) {
 		if (avail & mask) {
-			if (len-- == 0)
+			if ((p = header_bytes(a, 1)) == NULL)
 				return (-1);
-			*val |= ((uint64_t)*p++) << (8 * i);
+			*val |= ((uint64_t)*p) << (8 * i);
 			mask >>= 1;
 			continue;
 		}
 		*val += (avail & (mask -1)) << (8 * i);
 		break;
 	}
-	return (p - _p);
+	return (0);
 }
 
 static int
-read_Bools(unsigned char *data, size_t num, const unsigned char *p, size_t len)
+read_Bools(struct archive_read *a, unsigned char *data, size_t num)
 {
-	const unsigned char *_p = p;
-	unsigned i, mask = 0, avail;
+	const unsigned char *p;
+	unsigned i, mask = 0, avail = 0;
 
 	for (i = 0; i < num; i++) {
 		if (mask == 0) {
-			if (len == 0)
+			if ((p = header_bytes(a, 1)) == NULL)
 				return (-1);
-			avail = *p++;
-			len--;
+			avail = *p;
 			mask = 0x80;
 		}
 		data[i] = (avail & mask)?1:0;
 		mask >>= 1;
 	}
-	return (p - _p);
+	return (0);
 }
 
 static void
@@ -1573,16 +1593,13 @@ free_Digest(struct _7z_digests *d)
 }
 
 static int
-read_Digests(struct _7z_digests *d, size_t num, const unsigned char *p,
-    size_t len)
+read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num)
 {
-	const unsigned char *_p = p;
+	const unsigned char *p;
 	unsigned i;
 
 	memset(d, 0, sizeof(*d));
 
-	if (len == 0)
-		return (-1);
 
 	d->defineds = malloc(num);
 	if (d->defineds == NULL)
@@ -1590,13 +1607,11 @@ read_Digests(struct _7z_digests *d, size_t num, const unsigned char *p,
 	/*
 	 * Read Bools.
 	 */
-	len--;
-	if (*p++ == 0) {
-		int r = read_Bools(d->defineds, num, p, len);
-		if (r < 0)
+	if ((p = header_bytes(a, 1)) == NULL)
+		return (-1);
+	if (*p == 0) {
+		if (read_Bools(a, d->defineds, num) < 0)
 			return (-1);
-		p += r;
-		len -= r;
 	} else
 		/* All are defined */
 		memset(d->defineds, 1, num);
@@ -1604,17 +1619,15 @@ read_Digests(struct _7z_digests *d, size_t num, const unsigned char *p,
 	d->digests = calloc(num, sizeof(*d->digests));
 	if (d->digests == NULL)
 		return (-1);
-	if (len < 4 * num)
-		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);
-			p += 4;
-			len -= 4;
 		}
 	}
 
-	return (p - _p);
+	return (0);
 }
 
 static void
@@ -1626,62 +1639,55 @@ free_PackInfo(struct _7z_pack_info *pi)
 }
 
 static int
-read_PackInfo(struct _7z_pack_info *pi, const unsigned char *p, size_t len)
+read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
 {
-	const unsigned char *_p = p;
+	const unsigned char *p;
 	unsigned i;
-	int r;
 
 	memset(pi, 0, sizeof(*pi));
 
-	if (len < 3 || *p++ != kPackInfo)
-		return (-1);
-	--len;
-
 	/*
 	 * Read PackPos.
 	 */
-	r = parse_7zip_uint64(p, len, &(pi->pos));
-	if (r < 0)
-		return (r);
-	p += r;
-	len -= r;
+	if (parse_7zip_uint64(a, &(pi->pos)) < 0)
+		return (-1);
 
 	/*
 	 * Read NumPackStreams.
 	 */
-	r = parse_7zip_uint64(p, len, &(pi->numPackStreams));
-	if (r < 0 || pi->numPackStreams == 0)
-		return (r);
-	p += r;
-	len -= r;
+	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 (len >= 1 && *p == kEnd)
+	if ((p = header_bytes(a, 1)) == NULL)
+		return (-1);
+	if (*p == kEnd)
 		/* PackSizes[num] are not present. */
-		return (p - _p + 1);
-	if (len < 1 + pi->numPackStreams || *p++ != kSize)
+		return (0);
+	if (*p != kSize)
 		return (-1);
-	--len;
 	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++) {
-		r = parse_7zip_uint64(p, len, &(pi->sizes[i]));
-		if (r < 0)
+		if (parse_7zip_uint64(a, &(pi->sizes[i])) < 0)
 			return (-1);
-		p += r;
-		len -= r;
 	}
 
 	/*
 	 * Read PackStreamDigests[num]
 	 */
-	if (len >= 1 && *p == kEnd) {
+	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));
@@ -1689,25 +1695,23 @@ read_PackInfo(struct _7z_pack_info *pi, const unsigned char *p, size_t len)
 		    calloc(pi->numPackStreams, sizeof(*pi->digest.digests));
 		if (pi->digest.defineds == NULL || pi->digest.digests == NULL)
 			return (-1);
-		return (p - _p + 1);
+		return (0);
 	}
 
-	if (len < 1 + pi->numPackStreams || *p++ != kSize)
+	if (*p != kSize)
 		return (-1);
-	--len;
 
-	r = read_Digests(&(pi->digest), pi->numPackStreams, p, len);
-	if (r < 0)
+	if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0)
 		return (-1);
-	p += r;
-	len -= r;
 
 	/*
 	 *  Must be marked by kEnd.
 	 */
-	if (len == 0 || *p++ != kEnd)
+	if ((p = header_bytes(a, 1)) == NULL)
+		return (-1);
+	if (*p != kEnd)
 		return (-1);
-	return (p - _p);
+	return (0);
 }
 
 static void
@@ -1727,12 +1731,12 @@ free_Folder(struct _7z_folder *f)
 }
 
 static int
-read_Folder(struct _7z_folder *f, const unsigned char *p, size_t len)
+read_Folder(struct archive_read *a, struct _7z_folder *f)
 {
-	const unsigned char *_p = p;
+	struct _7zip *zip = (struct _7zip *)a->format->data;
+	const unsigned char *p;
 	uint64_t numInStreamsTotal = 0;
 	uint64_t numOutStreamsTotal = 0;
-	int r;
 	unsigned i;
 
 	memset(f, 0, sizeof(*f));
@@ -1740,11 +1744,11 @@ read_Folder(struct _7z_folder *f, const unsigned char *p, size_t len)
 	/*
 	 * Read NumCoders.
 	 */
-	r = parse_7zip_uint64(p, len, &(f->numCoders));
-	if (r < 0)
+	if (parse_7zip_uint64(a, &(f->numCoders)) < 0)
+		return (-1);
+	if (f->numCoders > 4)
+		/* Too many coders. */
 		return (-1);
-	p += r;
-	len -= r;
 
 	f->coders = calloc(f->numCoders, sizeof(*f->coders));
 	if (f->coders == NULL)
@@ -1753,7 +1757,7 @@ read_Folder(struct _7z_folder *f, const unsigned char *p, size_t len)
 		size_t codec_size;
 		int simple, attr;
 
-		if (len == 0)
+		if ((p = header_bytes(a, 1)) == NULL)
 			return (-1);
 		/*
 		 * 0:3 CodecIdSize
@@ -1768,46 +1772,37 @@ read_Folder(struct _7z_folder *f, const unsigned char *p, size_t len)
 		attr = *p & 0x20;
 		if (*p & 0x80)
 			return (-1);/* Not supported. */
-		p++;
-		len--;
 
 		/*
 		 * Read Decompression Method IDs.
 		 */
-		if (len < codec_size)
+		if ((p = header_bytes(a, codec_size)) == NULL)
 			return (-1);
 
 		f->coders[i].codec = decode_codec_id(p, codec_size);
-		p += codec_size;
-		len -= codec_size;
 
 		if (simple) {
 			f->coders[i].numInStreams = 1;
 			f->coders[i].numOutStreams = 1;
 		} else {
-			r = parse_7zip_uint64(p, len,
-			    &(f->coders[i].numInStreams));
-			if (r < 0)
+			if (parse_7zip_uint64(
+			    a, &(f->coders[i].numInStreams)) < 0)
 				return (-1);
-			p += r;
-			len -= r;
-			r = parse_7zip_uint64(p, len,
-			    &(f->coders[i].numOutStreams));
-			if (r < 0)
+			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);
-			p += r;
-			len -= r;
 		}
 
 		if (attr) {
-			r = parse_7zip_uint64(p, len,
-				&(f->coders[i].propertiesSize));
-			if (r < 0)
+			if (parse_7zip_uint64(
+			    a, &(f->coders[i].propertiesSize)) < 0)
 				return (-1);
-			p += r;
-			len -= r;
-
-			if (len < f->coders[i].propertiesSize)
+			if ((p = header_bytes(
+			    a, f->coders[i].propertiesSize)) == NULL)
 				return (-1);
 			f->coders[i].properties =
 			    malloc(f->coders[i].propertiesSize);
@@ -1815,8 +1810,6 @@ read_Folder(struct _7z_folder *f, const unsigned char *p, size_t len)
 				return (-1);
 			memcpy(f->coders[i].properties, p,
 			    f->coders[i].propertiesSize);
-			p += f->coders[i].propertiesSize;
-			len -= f->coders[i].propertiesSize;
 		}
 
 		numInStreamsTotal += f->coders[i].numInStreams;
@@ -1828,20 +1821,20 @@ read_Folder(struct _7z_folder *f, const unsigned char *p, size_t len)
 		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++) {
-		r = parse_7zip_uint64(p, len, &(f->bindPairs[i].inIndex));
-		if (r < 0)
+		if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
 			return (-1);
-		p += r;
-		len -= r;
-		r = parse_7zip_uint64(p, len, &(f->bindPairs[i].outIndex));
-		if (r < 0)
+		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);
-		p += r;
-		len -= r;
 	}
 
 	f->numPackedStreams = numInStreamsTotal - f->numBindPairs;
@@ -1864,17 +1857,16 @@ read_Folder(struct _7z_folder *f, const unsigned char *p, size_t len)
 		f->packedStreams[0] = i;
 	} else {
 		for (i = 0; i < f->numPackedStreams; i++) {
-			r = parse_7zip_uint64(p, len, &(f->packedStreams[i]));
-			if (r < 0)
+			if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)
+				return (-1);
+			if (1000000 < f->packedStreams[i])
 				return (-1);
-			p += r;
-			len -= r;
 		}
 	}
 	f->numInStreams = numInStreamsTotal;
 	f->numOutStreams = numOutStreamsTotal;
 
-	return (p - _p);
+	return (0);
 }
 
 static void
@@ -1890,65 +1882,55 @@ free_CodersInfo(struct _7z_coders_info *ci)
 }
 
 static int
-read_CodersInfo(struct _7z_coders_info *ci, const unsigned char *p, size_t len)
+read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
 {
-	const unsigned char *_p = p;
+	const unsigned char *p;
 	struct _7z_digests digest;
-	unsigned i, external;
-	int r;
+	unsigned i;
 
 	memset(ci, 0, sizeof(*ci));
 	memset(&digest, 0, sizeof(digest));
 
-	if (len < 3 || *p++ != kUnPackInfo)
+	if ((p = header_bytes(a, 1)) == NULL)
 		goto failed;
-	--len;
-
-	if (len < 3 || *p++ != kFolder)
+	if (*p != kFolder)
 		goto failed;
-	--len;
 
 	/*
 	 * Read NumFolders.
 	 */
-	r = parse_7zip_uint64(p, len, &(ci->numFolders));
-	if (r < 0)
+	if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
 		goto failed;
-	p += r;
-	len -= r;
+	if (1000000 < ci->numFolders)
+			return (-1);
 
 	/*
 	 * Read External.
 	 */
-	if (len == 0)
+	if ((p = header_bytes(a, 1)) == NULL)
 		goto failed;
-	external = *p++;
-	len --;
-	switch (external) {
+	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++) {
-			r = read_Folder(&(ci->folders[i]), p, len);
-			if (r < 0)
+			if (read_Folder(a, &(ci->folders[i])) < 0)
 				goto failed;
-			p += r;
-			len -= r;
 		}
 		break;
 	case 1:
-		r = parse_7zip_uint64(p, len, &(ci->dataStreamIndex));
-		if (r < 0)
-			return (r);
-		p += r;
-		len -= r;
+		if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
+			return (-1);
+		if (1000000 < ci->dataStreamIndex)
+			return (-1);
 		break;
 	}
 
-	if (len < 1 + ci->numFolders || *p++ != kCodersUnPackSize)
+	if ((p = header_bytes(a, 1)) == NULL)
+		goto failed;
+	if (*p != kCodersUnPackSize)
 		goto failed;
-	--len;
 
 	for (i = 0; i < ci->numFolders; i++) {
 		struct _7z_folder *folder = &(ci->folders[i]);
@@ -1959,30 +1941,22 @@ read_CodersInfo(struct _7z_coders_info *ci, const unsigned char *p, size_t len)
 		if (folder->unPackSize == NULL)
 			goto failed;
 		for (j = 0; j < folder->numOutStreams; j++) {
-			r = parse_7zip_uint64(p, len,
-			      &(folder->unPackSize[j]));
-			if (r < 0)
+			if (parse_7zip_uint64(a, &(folder->unPackSize[j])) < 0)
 				goto failed;
-			p += r;
-			len -= r;
 		}
 	}
 
 	/*
 	 * Read CRCs.
 	 */
-	if (len == 0)
+	if ((p = header_bytes(a, 1)) == NULL)
 		goto failed;
 	if (*p == kEnd)
-		return (p - _p + 1);
-	if (len < 1 + ci->numFolders || *p++ != kCRC)
+		return (0);
+	if (*p != kCRC)
 		goto failed;
-	--len;
-	r = read_Digests(&digest, ci->numFolders, p, len);
-	if (r < 0)
+	if (read_Digests(a, &digest, ci->numFolders) < 0)
 		goto failed;
-	p += r;
-	len -= r;
 	for (i = 0; i < ci->numFolders; i++) {
 		ci->folders[i].digest_defined = digest.defineds[i];
 		ci->folders[i].digest = digest.digests[i];
@@ -1991,10 +1965,12 @@ read_CodersInfo(struct _7z_coders_info *ci, const unsigned char *p, size_t len)
 	/*
 	 *  Must be kEnd.
 	 */
-	if (len == 0 || *p++ != kEnd)
+	if ((p = header_bytes(a, 1)) == NULL)
+		goto failed;
+	if (*p != kEnd)
 		goto failed;
 	free_Digest(&digest);
-	return (p - _p);
+	return (0);
 failed:
 	free_Digest(&digest);
 	return (-1);
@@ -2027,44 +2003,37 @@ free_SubStreamsInfo(struct _7z_substream_info *ss)
 }
 
 static int
-read_SubStreamsInfo(struct _7z_substream_info *ss, struct _7z_folder *f,
-    size_t numFolders, const unsigned char *p, size_t len)
+read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
+    struct _7z_folder *f, size_t numFolders)
 {
-	const unsigned char *_p = p;
+	const unsigned char *p;
 	uint64_t *usizes;
 	size_t unpack_streams;
-	int r, type;
+	int type;
 	unsigned i;
 	uint32_t numDigests;
 
 	memset(ss, 0, sizeof(*ss));
 
-	if (len < 2 || *p++ != kSubStreamsInfo)
-		return (-1);
-	--len;
-
 	for (i = 0; i < numFolders; i++)
 		f[i].numUnpackStreams = 1;
 
-	if (len < 1)
+	if ((p = header_bytes(a, 1)) == NULL)
 		return (-1);
-	type = *p++;
-	--len;
+	type = *p;
 
 	if (type == kNumUnPackStream) {
 		unpack_streams = 0;
 		for (i = 0; i < numFolders; i++) {
-			r = parse_7zip_uint64(p, len, &(f[i].numUnpackStreams));
-			if (r < 0)
+			if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)
+				return (-1);
+			if (1000000 < f[i].numUnpackStreams)
 				return (-1);
-			p += r;
-			len -= r;
 			unpack_streams += f[i].numUnpackStreams;
 		}
-		if (len < 1)
+		if ((p = header_bytes(a, 1)) == NULL)
 			return (-1);
-		type = *p++;
-		--len;
+		type = *p;
 	} else
 		unpack_streams = numFolders;
 
@@ -2092,11 +2061,8 @@ read_SubStreamsInfo(struct _7z_substream_info *ss, struct _7z_folder *f,
 		sum = 0;
 		if (type == kSize) {
 			for (pack = 1; pack < f[i].numUnpackStreams; pack++) {
-				r = parse_7zip_uint64(p, len, usizes);
-				if (r < 0)
+				if (parse_7zip_uint64(a, usizes) < 0)
 					return (-1);
-				p += r;
-				len -= r;
 				sum += *usizes++;
 			}
 		}
@@ -2104,10 +2070,9 @@ read_SubStreamsInfo(struct _7z_substream_info *ss, struct _7z_folder *f,
 	}
 
 	if (type == kSize) {
-		if (len < 1)
+		if ((p = header_bytes(a, 1)) == NULL)
 			return (-1);
-		type = *p++;
-		--len;
+		type = *p;
 	}
 
 	for (i = 0; i < unpack_streams; i++) {
@@ -2117,8 +2082,7 @@ read_SubStreamsInfo(struct _7z_substream_info *ss, struct _7z_folder *f,
 
 	numDigests = 0;
 	for (i = 0; i < numFolders; i++) {
-		if (f[i].numUnpackStreams != 1 ||
-			!f[i].digest_defined)
+		if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)
 			numDigests += f[i].numUnpackStreams;
 	}
 
@@ -2129,13 +2093,10 @@ read_SubStreamsInfo(struct _7z_substream_info *ss, struct _7z_folder *f,
 		int di = 0;
 
 		memset(&tmpDigests, 0, sizeof(tmpDigests));
-		r = read_Digests(&(tmpDigests), numDigests, p, len);
-		if (r < 0) {
+		if (read_Digests(a, &(tmpDigests), numDigests) < 0) {
 			free_Digest(&tmpDigests);
 			return (-1);
 		}
-		p += r;
-		len -= r;
 		for (i = 0; i < numFolders; i++) {
 			if (f[i].numUnpackStreams == 1 && f[i].digest_defined) {
 				*digestsDefined++ = 1;
@@ -2153,10 +2114,9 @@ read_SubStreamsInfo(struct _7z_substream_info *ss, struct _7z_folder *f,
 			}
 		}
 		free_Digest(&tmpDigests);
-		if (len < 1)
+		if ((p = header_bytes(a, 1)) == NULL)
 			return (-1);
-		type = *p++;
-		--len;
+		type = *p;
 	}
 
 	/*
@@ -2164,7 +2124,7 @@ read_SubStreamsInfo(struct _7z_substream_info *ss, struct _7z_folder *f,
 	 */
 	if (type != kEnd)
 		return (-1);
-	return (p - _p);
+	return (0);
 }
 
 static void
@@ -2176,24 +2136,24 @@ free_StreamsInfo(struct _7z_stream_info *si)
 }
 
 static int
-read_StreamsInfo(struct _7zip *zip, struct _7z_stream_info *si,
-    const unsigned char *p, size_t len)
+read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
 {
-	const unsigned char *_p = p;
+	struct _7zip *zip = (struct _7zip *)a->format->data;
+	const unsigned char *p;
 	unsigned i;
-	int r;
 
 	memset(si, 0, sizeof(*si));
 
-	if (len > 0 && *p == kPackInfo) {
+	if ((p = header_bytes(a, 1)) == NULL)
+		return (-1);
+	if (*p == kPackInfo) {
 		uint64_t packPos;
 
-		r = read_PackInfo(&(si->pi), p, len);
-		if (r < 0)
+		if (read_PackInfo(a, &(si->pi)) < 0)
 			return (-1);
-		p += r;
-		len -= r;
 
+		if (si->pi.positions == NULL || si->pi.sizes == NULL)
+			return (-1);
 		/*
 		 * Calculate packed stream positions.
 		 */
@@ -2204,16 +2164,15 @@ read_StreamsInfo(struct _7zip *zip, struct _7z_stream_info *si,
 			if (packPos > zip->header_offset)
 				return (-1);
 		}
+		if ((p = header_bytes(a, 1)) == NULL)
+			return (-1);
 	}
-	if (len > 0 && *p == kUnPackInfo) {
+	if (*p == kUnPackInfo) {
 		uint32_t packIndex;
 		struct _7z_folder *f;
 
-		r = read_CodersInfo(&(si->ci), p, len);
-		if (r < 0)
+		if (read_CodersInfo(a, &(si->ci)) < 0)
 			return (-1);
-		p += r;
-		len -= r;
 
 		/*
 		 * Calculate packed stream indexes.
@@ -2226,22 +2185,24 @@ read_StreamsInfo(struct _7zip *zip, struct _7z_stream_info *si,
 			if (packIndex > si->pi.numPackStreams)
 				return (-1);
 		}
+		if ((p = header_bytes(a, 1)) == NULL)
+			return (-1);
 	}
-	if (len > 0 && *p == kSubStreamsInfo) {
-		r = read_SubStreamsInfo(&(si->ss),
-		    si->ci.folders, si->ci.numFolders, p, len);
-		if (r < 0)
+
+	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);
-		p += r;
-		len -= r;
 	}
 
 	/*
 	 *  Must be kEnd.
 	 */
-	if (len == 0 || *p++ != kEnd)
+	if (*p != kEnd)
 		return (-1);
-	return (p - _p);
+	return (0);
 }
 
 static void
@@ -2254,71 +2215,69 @@ free_Header(struct _7z_header_info *h)
 }
 
 static int
-read_Header(struct _7zip *zip, struct _7z_header_info *h,
-    const unsigned char *p, size_t len)
+read_Header(struct archive_read *a, struct _7z_header_info *h,
+    int check_header_id)
 {
-	const unsigned char *_p = p;
+	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, r, sindex;
+	int eindex, empty_streams, sindex;
 
-	if (len < 2 || *p++ != kHeader)
-		return (-1);
-	len--;
+	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) {
-		p++;
-		len--;
-
 		for (;;) {
 			uint64_t size;
-			int atype = *p++;
-			len--;
-			if (atype == 0)
+			if ((p = header_bytes(a, 1)) == NULL)
+				return (-1);
+			if (*p == 0)
 				break;
-			r = parse_7zip_uint64(p, len, &size);
-			if (r < 0 || len < r + size)
+			if (parse_7zip_uint64(a, &size) < 0)
 				return (-1);
-			p += r + size;
-			len -= r + size;
 		}
+		if ((p = header_bytes(a, 1)) == NULL)
+			return (-1);
 	}
 
 	/*
 	 * Read MainStreamsInfo.
 	 */
 	if (*p == kMainStreamsInfo) {
-		p++;
-		len--;
-		r = read_StreamsInfo(zip, &(zip->si), p, len);
-		if (r < 0)
+		if (read_StreamsInfo(a, &(zip->si)) < 0)
+			return (-1);
+		if ((p = header_bytes(a, 1)) == NULL)
 			return (-1);
-		p += r;
-		len -= r;
 	}
-	if (len == 0)
-		return (-1);
 	if (*p == kEnd)
-		return (p - _p + 1);
+		return (0);
 
 	/*
 	 * Read FilesInfo.
 	 */
-	if (len < 2 || *p++ != kFilesInfo)
+	if (*p != kFilesInfo)
 		return (-1);
-	len--;
 
-	r = parse_7zip_uint64(p, len, &(zip->numFiles));
-	if (r < 0)
+	if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
 		return (-1);
-	p += r;
-	len -= r;
+	if (1000000 < zip->numFiles)
+			return (-1);
 
 	zip->entries = calloc(zip->numFiles, sizeof(*zip->entries));
 	if (zip->entries == NULL)
@@ -2331,20 +2290,17 @@ read_Header(struct _7zip *zip, struct _7z_header_info *h,
 		uint64_t size;
 		size_t ll;
 
-		if (len < 1)
+		if ((p = header_bytes(a, 1)) == NULL)
 			return (-1);
-		type = *p++;
-		len--;
+		type = *p;
 		if (type == kEnd)
 			break;
 
-		r = parse_7zip_uint64(p, len, &size);
-		if (r < 0 || len < size)
+		if (parse_7zip_uint64(a, &size) < 0)
+			return (-1);
+		if (zip->header_bytes_remaining < size)
 			return (-1);
-		p += r;
-		len -= r;
 		ll = (size_t)size;
-		len -= ll;
 
 		switch (type) {
 		case kEmptyStream:
@@ -2352,12 +2308,9 @@ read_Header(struct _7zip *zip, struct _7z_header_info *h,
 			    sizeof(*h->emptyStreamBools));
 			if (h->emptyStreamBools == NULL)
 				return (-1);
-			r = read_Bools(h->emptyStreamBools, zip->numFiles,
-			    p, ll);
-			if (r < 0)
+			if (read_Bools(
+			    a, h->emptyStreamBools, zip->numFiles) < 0)
 				return (-1);
-			p += r;
-			ll -= r;
 			empty_streams = 0;
 			for (i = 0; i < zip->numFiles; i++) {
 				if (h->emptyStreamBools[i])
@@ -2369,48 +2322,59 @@ read_Header(struct _7zip *zip, struct _7z_header_info *h,
 			    sizeof(*h->emptyFileBools));
 			if (h->emptyFileBools == NULL)
 				return (-1);
-			r = read_Bools(h->emptyFileBools, empty_streams,
-			    p, len);
-			if (r < 0)
+			if (read_Bools(a, h->emptyFileBools, empty_streams) < 0)
 				return (-1);
-			p += r;
-			ll -= r;
 			break;
 		case kAnti:
 			h->antiBools = calloc(empty_streams,
 			    sizeof(*h->antiBools));
 			if (h->antiBools == NULL)
 				return (-1);
-			r = read_Bools(h->antiBools, empty_streams, p, len);
-			if (r < 0)
+			if (read_Bools(a, h->antiBools, empty_streams) < 0)
 				return (-1);
-			p += r;
-			ll -= r;
 			break;
 		case kCTime:
 		case kATime:
 		case kMTime:
-			r = read_Times(zip, h, type, p, ll);
-			if (r < 0)
+			if (read_Times(a, h, type) < 0)
 				return (-1);
-			p += r;
-			ll -= r;
 			break;
 		case kName:
 		{
 			unsigned char *np;
-			size_t nl;
+			size_t nl, nb;
 
-			if (ll < 1)
+			/* Skip one byte. */
+			if ((p = header_bytes(a, 1)) == NULL)
 				return (-1);
-			p++; ll--;/* Skip one byte. */
+			ll--;
+
 			if ((ll & 1) || ll < zip->numFiles * 4)
 				return (-1);
 
 			zip->entry_names = malloc(ll);
 			if (zip->entry_names == NULL)
 				return (-1);
-			memcpy(zip->entry_names, p, ll);
+			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;
 
@@ -2437,11 +2401,9 @@ read_Header(struct _7zip *zip, struct _7z_header_info *h,
 		{
 			int allAreDefined;
 
-			if (ll < 2)
+			if ((p = header_bytes(a, 2)) == NULL)
 				return (-1);
-			allAreDefined = *p++;
-			--ll;
-			p++; --ll;/* Skip one byte. */
+			allAreDefined = *p;
 			h->attrBools = calloc(zip->numFiles,
 			    sizeof(*h->attrBools));
 			if (h->attrBools == NULL)
@@ -2449,29 +2411,24 @@ read_Header(struct _7zip *zip, struct _7z_header_info *h,
 			if (allAreDefined)
 				memset(h->attrBools, 1, zip->numFiles);
 			else {
-				r = read_Bools(h->attrBools,
-				      zip->numFiles, p, ll);
-				if (r < 0)
+				if (read_Bools(a, h->attrBools,
+				      zip->numFiles) < 0)
 					return (-1);
-				p += r;
-				ll -= r;
 			}
 			for (i = 0; i < zip->numFiles; i++) {
 				if (h->attrBools[i]) {
-					if (ll < 4)
+					if ((p = header_bytes(a, 4)) == NULL)
 						return (-1);
 					entries[i].attr = archive_le32dec(p);
-					p += 4;
-					ll -= 4;
 				}
 			}
 			break;
 		}
 		default:
+			if (header_bytes(a, ll) == NULL)
+				return (-1);
 			break;
 		}
-		/* Skip remaining data. */
-		p += ll;
 	}
 
 	/*
@@ -2481,8 +2438,7 @@ read_Header(struct _7zip *zip, struct _7z_header_info *h,
 	eindex = sindex = 0;
 	folderIndex = indexInFolder = 0;
 	for (i = 0; i < zip->numFiles; i++) {
-		if (h->emptyStreamBools == NULL ||
-		    h->emptyStreamBools[i] == 0)
+		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;
@@ -2556,7 +2512,7 @@ read_Header(struct _7zip *zip, struct _7z_header_info *h,
 		}
 	}
 
-	return (p - _p);
+	return (0);
 }
 
 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
@@ -2577,50 +2533,44 @@ fileTimeToUtc(uint64_t fileTime, time_t *time, long *ns)
 }
 
 static int
-read_Times(struct _7zip *zip, struct _7z_header_info *h, int type,
-    const unsigned char *p, size_t len)
+read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
 {
-	const unsigned char *_p = p;
+	struct _7zip *zip = (struct _7zip *)a->format->data;
+	const unsigned char *p;
 	struct _7zip_entry *entries = zip->entries;
 	unsigned char *timeBools;
-	int r;
-	int allAreDefined, external;
+	int allAreDefined;
 	unsigned i;
 
 	timeBools = calloc(zip->numFiles, sizeof(*timeBools));
 	if (timeBools == NULL)
 		return (-1);
 
-	if (len < 1)
+	/* Read allAreDefined. */
+	if ((p = header_bytes(a, 1)) == NULL)
 		goto failed;
-	allAreDefined = *p++;
-	len--;
+	allAreDefined = *p;
 	if (allAreDefined)
 		memset(timeBools, 1, zip->numFiles);
 	else {
-		r = read_Bools(timeBools, zip->numFiles, p, len);
-		if (r < 0)
+		if (read_Bools(a, timeBools, zip->numFiles) < 0)
 			goto failed;
-		p += r;
-		len -= r;
 	}
 
-	if (len < 1)
+	/* Read external. */
+	if ((p = header_bytes(a, 1)) == NULL)
 		goto failed;
-	external = *p++;
-	len--;
-	if (external) {
-		r = parse_7zip_uint64(p, len, &(h->dataIndex));
-		if (r < 0)
+	if (*p) {
+		if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
 			goto failed;
-		p += r;
-		len -= r;
+		if (1000000 < h->dataIndex)
+			return (-1);
 	}
 
 	for (i = 0; i < zip->numFiles; i++) {
 		if (!timeBools[i])
 			continue;
-		if (len < 8)
+		if ((p = header_bytes(a, 8)) == NULL)
 			goto failed;
 		switch (type) {
 		case kCTime:
@@ -2642,29 +2592,22 @@ read_Times(struct _7zip *zip, struct _7z_header_info *h, int type,
 			entries[i].flg |= MTIME_IS_SET;
 			break;
 		}
-		p += 8;
-		len -= 8;
 	}
 
 	free(timeBools);
-	return (p - _p);
+	return (0);
 failed:
 	free(timeBools);
 	return (-1);
 }
 
-static ssize_t
-decode_header_image(struct archive_read *a, struct _7zip *zip,
-    struct _7z_stream_info *si, const unsigned char *p, uint64_t len,
-    const void **image)
+static int
+decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)
 {
-	const unsigned char *v;
-	size_t vsize;
-	int r;
+	struct _7zip *zip = (struct _7zip *)a->format->data;
 
 	errno = 0;
-	r = read_StreamsInfo(zip, si, p, len);
-	if (r < 0) {
+	if (read_StreamsInfo(a, si) < 0) {
 		if (errno == ENOMEM)
 			archive_set_error(&a->archive, -1,
 			    "Couldn't allocate memory");
@@ -2686,79 +2629,40 @@ decode_header_image(struct archive_read *a, struct _7zip *zip,
 		return (ARCHIVE_FATAL);
 	}
 
-	r = setup_decode_folder(a, si->ci.folders, 1);
-	if (r != ARCHIVE_OK)
-		return (ARCHIVE_FATAL);
-
-	/* Get an uncompressed header size. */
-	vsize = (size_t)zip->folder_outbytes_remaining;
-
-	/*
-	 * Allocate an uncompressed buffer for the header image.
-	 */
-	zip->uncompressed_buffer_size = 64 * 1024;
-	if (vsize > zip->uncompressed_buffer_size)
-		zip->uncompressed_buffer_size = vsize;
-	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);
-	}
+	return (ARCHIVE_OK);
+}
 
-	/* Get the bytes we can read to decode the header. */
-	zip->pack_stream_inbytes_remaining = si->pi.sizes[0];
+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;
 
-	/* Seek the read point. */
-	if (__archive_read_seek(a, si->pi.pos + zip->seek_base, SEEK_SET) < 0)
-		return (ARCHIVE_FATAL);
-	zip->header_offset = si->pi.pos;
+	if (zip->header_bytes_remaining < rbytes)
+		return (NULL);
+	if (zip->pack_stream_bytes_unconsumed)
+		read_consume(a);
 
-	/* Extract a pack stream. */
-	r = extract_pack_stream(a);
-	if (r < 0)
-		return (r);
-	for (;;) {
+	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 = get_uncompressed_data(a, image, vsize);
-		if (bytes < 0)
-			return (r);
-		if (bytes != vsize) {
-			if (*image != zip->uncompressed_buffer) {
-				/* This might happen if the coder was COPY.
-				 * We have to make sure we read a full plain
-				 * header image. */
-				if (NULL==__archive_read_ahead(a, vsize, NULL))
-					return (ARCHIVE_FATAL);
-				continue;
-			} else {
-				archive_set_error(&a->archive, -1,
-				    "Malformed 7-Zip archive file");
-				return (ARCHIVE_FATAL);
-			}
-		}
-		break;
-	}
-	v = *image;
-
-	/* Clean up variables which will not 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;
 
-	/* Check the header CRC. */
-	if (si->ci.folders[0].digest_defined){
-		uint32_t c = crc32(0, v, vsize);
-		if (c != si->ci.folders[0].digest) {
-			archive_set_error(&a->archive, -1, "Header CRC error");
-			return (ARCHIVE_FATAL);
-		}
+		bytes = read_stream(a, &buff, rbytes, rbytes);
+		if (bytes <= 0)
+			return (NULL);
+		zip->header_bytes_remaining -= bytes;
+		p = buff;
 	}
-	return ((ssize_t)vsize);
+
+	/* Update checksum */
+	zip->header_crc32 = crc32(zip->header_crc32, p, rbytes);
+	return (p);
 }
 
 static int
@@ -2766,13 +2670,11 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
     struct _7z_header_info *header)
 {
 	const unsigned char *p;
-	const void *image;
-	uint64_t len;
 	uint64_t next_header_offset;
 	uint64_t next_header_size;
 	uint32_t next_header_crc;
-	ssize_t bytes_avail, image_bytes;
-	int r;
+	ssize_t bytes_avail;
+	int check_header_crc, r;
 
 	if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
 		return (ARCHIVE_FATAL);
@@ -2782,7 +2684,7 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
 		r = skip_sfx(a, bytes_avail);
 		if (r < ARCHIVE_WARN)
 			return (r);
-		if ((p = __archive_read_ahead(a, 32, NULL)) == NULL)
+		if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
 			return (ARCHIVE_FATAL);
 	}
 	zip->seek_base += 32;
@@ -2810,45 +2712,71 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
 		archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
 		return (ARCHIVE_FATAL);
 	}
-	if (__archive_read_seek(a, next_header_offset + zip->seek_base,
-	    SEEK_SET) < 0)
-		return (ARCHIVE_FATAL);
+	__archive_read_consume(a, 32);
+	if (next_header_offset != 0) {
+		if (bytes_avail >= 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 = __archive_read_ahead(a, next_header_size, NULL)) == NULL)
-		return (ARCHIVE_FATAL);
-
-	if (crc32(0, p, next_header_size) != next_header_crc) {
-		archive_set_error(&a->archive, -1, "Damaged 7-Zip archive");
+	if ((p = header_bytes(a, 1)) == NULL) {
+		archive_set_error(&a->archive,
+		    ARCHIVE_ERRNO_FILE_FORMAT,
+		    "Truncated 7-Zip file body");
 		return (ARCHIVE_FATAL);
 	}
-
-	len = next_header_size;
 	/* Parse ArchiveProperties. */
 	switch (p[0]) {
 	case kEncodedHeader:
-		p++;
-		len--;
-
 		/*
 		 * The archive has an encoded header and we have to decode it
 		 * in order to parse the header correctly.
 		 */
-		image_bytes =
-		    decode_header_image(a, zip, &(zip->si), p, len, &image);
+		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 (image_bytes < 0)
+		if (r < 0)
 			return (ARCHIVE_FATAL);
-		p = image;
-		len = image_bytes;
+		zip->header_is_encoded = 1;
+		zip->header_crc32 = 0;
 		/* FALL THROUGH */
 	case kHeader:
 		/*
 		 * Parse the header.
 		 */
 		errno = 0;
-		r = read_Header(zip, header, p, len);
+		r = read_Header(a, header, zip->header_is_encoded);
 		if (r < 0) {
 			if (errno == ENOMEM)
 				archive_set_error(&a->archive, -1,
@@ -2858,7 +2786,18 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
 				    "Damaged 7-Zip archive");
 			return (ARCHIVE_FATAL);
 		}
-		if (len - r == 0 || p[r] != kEnd) {
+
+		/*
+		 *  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);
@@ -2869,24 +2808,21 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
 		    "Unexpected Property ID = %X", p[0]);
 		return (ARCHIVE_FATAL);
 	}
-	zip->stream_offset = -1;
 
-	/*
-	 * If the uncompressed buffer was allocated more than 64K for
-	 * the header image, release it.
-	 */
-	if (zip->uncompressed_buffer != NULL &&
-	    zip->uncompressed_buffer_size != 64 * 1024) {
-		free(zip->uncompressed_buffer);
-		zip->uncompressed_buffer = NULL;
-		zip->uncompressed_buffer_size = 0;
-	}
+	/* 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)
+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;
@@ -2922,6 +2858,15 @@ get_uncompressed_data(struct archive_read *a, const void **buff, size_t size)
 		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;
@@ -2935,14 +2880,16 @@ get_uncompressed_data(struct archive_read *a, const void **buff, size_t size)
 }
 
 static ssize_t
-extract_pack_stream(struct archive_read *a)
+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 == -1) {
-		if (__archive_read_ahead(a, 1, &bytes_avail) == NULL
+		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,
@@ -2961,7 +2908,11 @@ extract_pack_stream(struct archive_read *a)
 
 	/* If the buffer hasn't been allocated, allocate it now. */
 	if (zip->uncompressed_buffer == NULL) {
-		zip->uncompressed_buffer_size = 64 * 1024;
+		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) {
@@ -2969,8 +2920,46 @@ extract_pack_stream(struct archive_read *a)
 			    "No memory for 7-Zip decompression");
 			return (ARCHIVE_FATAL);
 		}
-	}
-	zip->uncompressed_buffer_bytes_remaining = 0;
+		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;
@@ -3025,6 +3014,10 @@ extract_pack_stream(struct archive_read *a)
 		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;
@@ -3035,6 +3028,11 @@ extract_pack_stream(struct archive_read *a)
 		}
 		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);
 }
@@ -3065,7 +3063,8 @@ seek_pack(struct archive_read *a)
 }
 
 static ssize_t
-read_stream(struct archive_read *a, const void **buff, size_t size)
+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;
@@ -3073,29 +3072,36 @@ read_stream(struct archive_read *a, const void **buff, size_t size)
 
 	if (zip->uncompressed_buffer_bytes_remaining == 0) {
 		if (zip->pack_stream_inbytes_remaining > 0) {
-			r = extract_pack_stream(a);
+			r = extract_pack_stream(a, 0);
 			if (r < 0)
 				return (r);
-			return (get_uncompressed_data(a, buff, size));
+			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);
+			r = extract_pack_stream(a, 0);
 			if (r < 0)
 				return (r);
-			return (get_uncompressed_data(a, buff, size));
+			return (get_uncompressed_data(a, buff, size, minimum));
 		}
 	} else
-		return (get_uncompressed_data(a, buff, size));
+		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)) {
@@ -3127,7 +3133,7 @@ read_stream(struct archive_read *a, const void **buff, size_t size)
 		return (r);
 
 	/* Extract a new pack stream. */
-	r = extract_pack_stream(a);
+	r = extract_pack_stream(a, 0);
 	if (r < 0)
 		return (r);
 
@@ -3139,12 +3145,12 @@ read_stream(struct archive_read *a, const void **buff, size_t size)
 
 		if (zip->uncompressed_buffer_bytes_remaining == 0) {
 			if (zip->pack_stream_inbytes_remaining > 0) {
-				r = extract_pack_stream(a);
+				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);
+				r = extract_pack_stream(a, 0);
 				if (r < 0)
 					return (r);
 			} else {
@@ -3154,7 +3160,7 @@ read_stream(struct archive_read *a, const void **buff, size_t size)
 				return (ARCHIVE_FATAL);
 			}
 		}
-		skipped = get_uncompressed_data(a, buff, skip_bytes);
+		skipped = get_uncompressed_data(a, buff, skip_bytes, 0);
 		if (skipped < 0)
 			return (skipped);
 		skip_bytes -= skipped;
@@ -3162,7 +3168,7 @@ read_stream(struct archive_read *a, const void **buff, size_t size)
 			read_consume(a);
 	}
 
-	return (get_uncompressed_data(a, buff, size));
+	return (get_uncompressed_data(a, buff, size, minimum));
 }
 
 static int
@@ -3336,11 +3342,12 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
 
 			/* Extract a sub stream. */
 			while (zip->pack_stream_inbytes_remaining > 0) {
-				r = extract_pack_stream(a);
+				r = extract_pack_stream(a, 0);
 				if (r < 0)
 					return (r);
 				bytes = get_uncompressed_data(a, &buff,
-				    zip->uncompressed_buffer_bytes_remaining);
+				    zip->uncompressed_buffer_bytes_remaining,
+				    0);
 				if (bytes < 0)
 					return ((int)bytes);
 				memcpy(b[i]+s[i], buff, bytes);
@@ -3412,7 +3419,7 @@ skip_stream(struct archive_read *a, size_t skip_bytes)
 	}
 
 	while (bytes) {
-		skipped_bytes = read_stream(a, &p, bytes);
+		skipped_bytes = read_stream(a, &p, bytes, 0);
 		if (skipped_bytes < 0)
 			return (skipped_bytes);
 		if (skipped_bytes == 0) {
@@ -3438,18 +3445,30 @@ skip_stream(struct archive_read *a, size_t skip_bytes)
 
 #define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
 
-static const unsigned char kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
-static const unsigned char kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
+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(uint8_t *data, size_t size, uint32_t ip, uint32_t *state)
+x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
 {
-	size_t bufferPos = 0, prevPosT;
-	uint32_t prevMask = *state & 0x7;
+	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;
-	ip += 5;
-	prevPosT = (size_t)0 - 1;
+
+	bufferPos = 0;
+	prevPosT = zip->bcj_prevPosT;
+	prevMask = zip->bcj_prevMask;
+	ip = zip->bcj_ip;
 
 	for (;;) {
 		uint8_t *p = data + bufferPos;
@@ -3508,9 +3527,9 @@ x86_Convert(uint8_t *data, size_t size, uint32_t ip, uint32_t *state)
 			bufferPos++;
 		}
 	}
-	prevPosT = bufferPos - prevPosT;
-	*state = ((prevPosT > 3) ? 
-			0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
+	zip->bcj_prevPosT = prevPosT;
+	zip->bcj_prevMask = prevMask;
+	zip->bcj_ip += bufferPos;
 	return (bufferPos);
 }
 
@@ -3545,7 +3564,7 @@ x86_Convert(uint8_t *data, size_t size, uint32_t ip, uint32_t *state)
 #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;
 
-ssize_t
+static ssize_t
 Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
 {
 	size_t inPos = 0, outPos = 0;
diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c
index a1bed4f..4f68ef8 100644
--- a/libarchive/archive_read_support_format_iso9660.c
+++ b/libarchive/archive_read_support_format_iso9660.c
@@ -1962,7 +1962,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
 		    (parent->re || parent->re_descendant))
 			file->re_descendant = 1;
 		if (file->cl_offset) {
-			struct file_info *p;
+			struct file_info *r;
 
 			if (parent == NULL || parent->parent == NULL) {
 				archive_set_error(&a->archive,
@@ -1990,8 +1990,8 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
 			 * Sanity check: cl_offset does not point at its
 			 * the parents or itself.
 			 */
-			for (p = parent; p; p = p->parent) {
-				if (p->offset == file->cl_offset) {
+			for (r = parent; r; r = r->parent) {
+				if (r->offset == file->cl_offset) {
 					archive_set_error(&a->archive,
 					    ARCHIVE_ERRNO_MISC,
 					    "Invalid Rockridge CL");
diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c
index de0e434..a812422 100644
--- a/libarchive/archive_read_support_format_zip.c
+++ b/libarchive/archive_read_support_format_zip.c
@@ -112,6 +112,8 @@ struct zip {
 };
 
 #define ZIP_LENGTH_AT_END	8
+#define ZIP_ENCRYPTED		(1<<0)	
+#define ZIP_STRONG_ENCRYPTED	(1<<6)	
 #define ZIP_UTF8_NAME		(1<<11)	
 
 static int	archive_read_format_zip_streamable_bid(struct archive_read *, int);
@@ -356,7 +358,32 @@ archive_read_format_zip_seekable_read_header(struct archive_read *a,
 	   typically faster (easier for I/O layer to optimize). */
 	__archive_read_seek(a, zip->entry->local_header_offset, SEEK_SET);
 	zip->unconsumed = 0;
-	return zip_read_local_file_header(a, entry, zip);
+	r = zip_read_local_file_header(a, entry, zip);
+	if (r != ARCHIVE_OK)
+		return r;
+	if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) {
+		const void *p;
+		size_t linkname_length = archive_entry_size(entry);
+
+		archive_entry_set_size(entry, 0);
+		p = __archive_read_ahead(a, linkname_length, NULL);
+		if (p == NULL) {
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Truncated Zip file");
+			return ARCHIVE_FATAL;
+		}
+
+		if (archive_entry_copy_symlink_l(entry, p, linkname_length,
+		    NULL) != 0) {
+			/* NOTE: If the last argument is NULL, this will
+			 * fail only by memeory allocation failure. */
+			archive_set_error(&a->archive, ENOMEM,
+			    "Can't allocate memory for Symlink");
+			return (ARCHIVE_FATAL);
+		}
+		/* TODO: handle character-set issues? */
+	}
+	return ARCHIVE_OK;
 }
 
 static int
@@ -722,6 +749,12 @@ archive_read_format_zip_read_data(struct archive_read *a,
 	if (AE_IFREG != (zip->entry->mode & AE_IFMT))
 		return (ARCHIVE_EOF);
 
+	if (zip->entry->flags & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+		    "Encrypted file is unsupported");
+		return (ARCHIVE_FAILED);
+	}
+
 	__archive_read_consume(a, zip->unconsumed);
 	zip->unconsumed = 0;
 
diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c
index 5e95dd7..4dec82d 100644
--- a/libarchive/archive_string.c
+++ b/libarchive/archive_string.c
@@ -212,7 +212,7 @@ static struct archive_string *
 archive_string_append(struct archive_string *as, const char *p, size_t s)
 {
 	if (archive_string_ensure(as, as->length + s + 1) == NULL)
-		__archive_errx(1, "Out of memory");
+		return (NULL);
 	memcpy(as->s + as->length, p, s);
 	as->length += s;
 	as->s[as->length] = 0;
@@ -223,7 +223,7 @@ static struct archive_wstring *
 archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s)
 {
 	if (archive_wstring_ensure(as, as->length + s + 1) == NULL)
-		__archive_errx(1, "Out of memory");
+		return (NULL);
 	wmemcpy(as->s + as->length, p, s);
 	as->length += s;
 	as->s[as->length] = 0;
@@ -233,13 +233,15 @@ archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s)
 void
 archive_string_concat(struct archive_string *dest, struct archive_string *src)
 {
-	archive_string_append(dest, src->s, src->length);
+	if (archive_string_append(dest, src->s, src->length) == NULL)
+		__archive_errx(1, "Out of memory");
 }
 
 void
 archive_wstring_concat(struct archive_wstring *dest, struct archive_wstring *src)
 {
-	archive_wstring_append(dest, src->s, src->length);
+	if (archive_wstring_append(dest, src->s, src->length) == NULL)
+		__archive_errx(1, "Out of memory");
 }
 
 void
@@ -346,7 +348,9 @@ archive_strncat(struct archive_string *as, const void *_p, size_t n)
 		pp++;
 		s++;
 	}
-	return (archive_string_append(as, p, s));
+	if ((as = archive_string_append(as, p, s)) == NULL)
+		__archive_errx(1, "Out of memory");
+	return (as);
 }
 
 struct archive_wstring *
@@ -362,7 +366,9 @@ archive_wstrncat(struct archive_wstring *as, const wchar_t *p, size_t n)
 		pp++;
 		s++;
 	}
-	return (archive_wstring_append(as, p, s));
+	if ((as = archive_wstring_append(as, p, s)) == NULL)
+		__archive_errx(1, "Out of memory");
+	return (as);
 }
 
 struct archive_string *
@@ -387,13 +393,17 @@ archive_wstrcat(struct archive_wstring *as, const wchar_t *p)
 struct archive_string *
 archive_strappend_char(struct archive_string *as, char c)
 {
-	return (archive_string_append(as, &c, 1));
+	if ((as = archive_string_append(as, &c, 1)) == NULL)
+		__archive_errx(1, "Out of memory");
+	return (as);
 }
 
 struct archive_wstring *
 archive_wstrappend_wchar(struct archive_wstring *as, wchar_t c)
 {
-	return (archive_wstring_append(as, &c, 1));
+	if ((as = archive_wstring_append(as, &c, 1)) == NULL)
+		__archive_errx(1, "Out of memory");
+	return (as);
 }
 
 /*
@@ -2080,14 +2090,8 @@ archive_strncat_in_locale(struct archive_string *as, const void *_p, size_t n,
 	 */
 	if (sc == NULL) {
 		length = mbsnbytes(_p, n);
-		/*
-		 * archive_string_append() will call archive_string_ensure()
-		 * but we cannot know if that call is failed or not. so
-		 * we call archive_string_ensure() here.
-		 */
-		if (archive_string_ensure(as, as->length + length + 1) == NULL)
-			return (-1);
-		archive_string_append(as, _p, length);
+		if (archive_string_append(as, _p, length) == NULL)
+			return (-1);/* No memory */
 		return (0);
 	}
 
@@ -2338,7 +2342,8 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
 	 * And then this checks all copied MBS can be WCS if so returns 0.
 	 */
 	if (sc->same) {
-		archive_string_append(as, _p, length);
+		if (archive_string_append(as, _p, length) == NULL)
+			return (-1);/* No memory */
 		return (invalid_mbs(_p, length, sc));
 	}
 
@@ -4115,10 +4120,14 @@ archive_mstring_copy_mbs_len_l(struct archive_mstring *aes,
 	 * characters because Windows platform cannot make locale UTF-8.
 	 */
 	if (sc == NULL) {
-		archive_string_append(&(aes->aes_mbs),
-		    mbs, mbsnbytes(mbs, len));
-		aes->aes_set = AES_SET_MBS;
-		r = 0;
+		if (archive_string_append(&(aes->aes_mbs),
+			mbs, mbsnbytes(mbs, len)) == NULL) {
+			aes->aes_set = 0;
+			r = -1;
+		} else {
+			aes->aes_set = AES_SET_MBS;
+			r = 0;
+		}
 #if defined(HAVE_ICONV)
 	} else if (sc != NULL && sc->cd_w != (iconv_t)-1) {
 		/*
diff --git a/libarchive/archive_util.3 b/libarchive/archive_util.3
index e07ac95..cd05d03 100644
--- a/libarchive/archive_util.3
+++ b/libarchive/archive_util.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_util.3 201098 2009-12-28 02:58:14Z kientzle $
 .\"
 .Dd January 8, 2005
-.Dt archive_util 3
+.Dt ARCHIVE_UTIL 3
 .Os
 .Sh NAME
 .Nm archive_clear_error ,
diff --git a/libarchive/archive_windows.c b/libarchive/archive_windows.c
index af104b8..0bb2a80 100644
--- a/libarchive/archive_windows.c
+++ b/libarchive/archive_windows.c
@@ -135,6 +135,11 @@ __la_win_permissive_name_w(const wchar_t *wname)
 	l = GetFullPathNameW(wname, 0, NULL, NULL);
 	if (l == 0)
 		return (NULL);
+	/* NOTE: GetFullPathNameW has a bug that if the length of the file
+	 * name is just one that return imcomplete buffer size. Thus, we 
+	 * have to add three to the size to allocate a sufficient buffer
+	 * size for the full-pathname of the file name. */
+	l += 3;
 	wnp = malloc(l * sizeof(wchar_t));
 	if (wnp == NULL)
 		return (NULL);
@@ -229,27 +234,6 @@ la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
 	return (handle);
 }
 
-/*
- * This fcntl is limited implementation.
- */
-int
-__la_fcntl(int fd, int cmd, int val)
-{
-	HANDLE handle;
-
-	handle = (HANDLE)_get_osfhandle(fd);
-	if (GetFileType(handle) == FILE_TYPE_PIPE) {
-		if (cmd == F_SETFL && val == 0) {
-			DWORD mode = PIPE_WAIT;
-			if (SetNamedPipeHandleState(
-			    handle, &mode, NULL, NULL) != 0)
-				return (0);
-		}
-	}
-	errno = EINVAL;
-	return (-1);
-}
-
 /* This can exceed MAX_PATH limitation. */
 int
 __la_open(const char *path, int flags, ...)
@@ -368,22 +352,6 @@ __la_read(int fd, void *buf, size_t nbytes)
 	if (nbytes == 0)
 		return (0);
 	handle = (HANDLE)_get_osfhandle(fd);
-	if (GetFileType(handle) == FILE_TYPE_PIPE) {
-		DWORD sta;
-		if (GetNamedPipeHandleState(
-		    handle, &sta, NULL, NULL, NULL, NULL, 0) != 0 &&
-		    (sta & PIPE_NOWAIT) == 0) {
-			DWORD avail = -1;
-			int cnt = 3;
-
-			while (PeekNamedPipe(
-			    handle, NULL, 0, NULL, &avail, NULL) != 0 &&
-			    avail == 0 && --cnt)
-				Sleep(100);
-			if (avail == 0)
-				return (0);
-		}
-	}
 	r = ReadFile(handle, buf, (uint32_t)nbytes,
 	    &bytes_read, NULL);
 	if (r == 0) {
diff --git a/libarchive/archive_windows.h b/libarchive/archive_windows.h
index b26811e..cfb3e97 100644
--- a/libarchive/archive_windows.h
+++ b/libarchive/archive_windows.h
@@ -90,7 +90,7 @@
 
 /* Alias the Windows _function to the POSIX equivalent. */
 #define	close		_close
-#define	fcntl		__la_fcntl
+#define	fcntl(fd, cmd, flg)	/* No operation. */		
 #ifndef fileno
 #define	fileno		_fileno
 #endif
@@ -243,7 +243,6 @@
 
 
 /* Replacement POSIX function */
-extern int	 __la_fcntl(int fd, int cmd, int val);
 extern int	 __la_fstat(int fd, struct stat *st);
 extern int	 __la_lstat(const char *path, struct stat *st);
 extern int	 __la_open(const char *path, int flags, ...);
diff --git a/libarchive/archive_write.3 b/libarchive/archive_write.3
index 1fa4245..f87386a 100644
--- a/libarchive/archive_write.3
+++ b/libarchive/archive_write.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $
 .\"
 .Dd March 23, 2011
-.Dt archive_write 3
+.Dt ARCHIVE_WRITE 3
 .Os
 .Sh NAME
 .Nm archive_write
diff --git a/libarchive/archive_write_blocksize.3 b/libarchive/archive_write_blocksize.3
index 239fa92..96c7538 100644
--- a/libarchive/archive_write_blocksize.3
+++ b/libarchive/archive_write_blocksize.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd March 23, 2011
-.Dt archive_write_blocksize 3
+.Dt ARCHIVE_WRITE_BLOCKSIZE 3
 .Os
 .Sh NAME
 .Nm archive_write_get_bytes_per_block ,
diff --git a/libarchive/archive_write_data.3 b/libarchive/archive_write_data.3
index 2c98b3e..fc399bc 100644
--- a/libarchive/archive_write_data.3
+++ b/libarchive/archive_write_data.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $
 .\"
 .Dd March 23, 2011
-.Dt archive_write 3
+.Dt ARCHIVE_WRITE 3
 .Os
 .Sh NAME
 .Nm archive_write_data
diff --git a/libarchive/archive_write_disk.3 b/libarchive/archive_write_disk.3
index 90bbdcf..ffadb04 100644
--- a/libarchive/archive_write_disk.3
+++ b/libarchive/archive_write_disk.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: src/lib/libarchive/archive_write_disk.3,v 1.4 2008/09/04 05:22:00 kientzle Exp $
 .\"
 .Dd August 5, 2008
-.Dt archive_write_disk 3
+.Dt ARCHIVE_WRITE_DISK 3
 .Os
 .Sh NAME
 .Nm archive_write_disk_new ,
diff --git a/libarchive/archive_write_disk_windows.c b/libarchive/archive_write_disk_windows.c
index 9df9ddc..2dc2d92 100644
--- a/libarchive/archive_write_disk_windows.c
+++ b/libarchive/archive_write_disk_windows.c
@@ -542,11 +542,36 @@ la_CreateHardLinkW(wchar_t *linkname, wchar_t *target)
 {
 	static BOOLEAN (WINAPI *f)(LPWSTR, LPWSTR, LPSECURITY_ATTRIBUTES);
 	static int set;
+	BOOL ret;
+
 	if (!set) {
 		set = 1;
 		f = la_GetFunctionKernel32("CreateHardLinkW");
 	}
-	return f == NULL ? 0 : (*f)(linkname, target, NULL);
+	if (!f)
+		return (0);
+	ret = (*f)(linkname, target, NULL);
+	if (!ret) {
+		/* Under windows 2000, it is necessary to remove
+		 * the "\\?\" prefix. */
+#define IS_UNC(name)	((name[0] == L'U' || name[0] == L'u') &&	\
+			 (name[1] == L'N' || name[1] == L'n') &&	\
+			 (name[2] == L'C' || name[2] == L'c') &&	\
+			 name[3] == L'\\')
+		if (!wcsncmp(linkname,L"\\\\?\\", 4)) {
+			linkname += 4;
+			if (IS_UNC(linkname))
+				linkname += 4;
+		}
+		if (!wcsncmp(target,L"\\\\?\\", 4)) {
+			target += 4;
+			if (IS_UNC(target))
+				target += 4;
+		}
+#undef IS_UNC
+		ret = (*f)(linkname, target, NULL);
+	}
+	return (ret);
 }
 
 static int
@@ -2207,6 +2232,7 @@ create_dir(struct archive_write_disk *a, wchar_t *path)
 			le->fixup |=TODO_MODE_BASE;
 			le->mode = mode_final;
 		}
+		free(full);
 		return (ARCHIVE_OK);
 	} else {
 		la_dosmaperr(GetLastError());
diff --git a/libarchive/archive_write_filter.3 b/libarchive/archive_write_filter.3
index f084a51..00438d4 100644
--- a/libarchive/archive_write_filter.3
+++ b/libarchive/archive_write_filter.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd March 23, 2011
-.Dt archive_write_filter 3
+.Dt ARCHIVE_WRITE_FILTER 3
 .Os
 .Sh NAME
 .Nm archive_write_add_filter_bzip2 ,
diff --git a/libarchive/archive_write_finish_entry.3 b/libarchive/archive_write_finish_entry.3
index 06c002e..3add601 100644
--- a/libarchive/archive_write_finish_entry.3
+++ b/libarchive/archive_write_finish_entry.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $
 .\"
 .Dd March 23, 2011
-.Dt archive_write_finish_entry 3
+.Dt ARCHIVE_WRITE_FINISH_ENTRY 3
 .Os
 .Sh NAME
 .Nm archive_write_finish_entry
diff --git a/libarchive/archive_write_format.3 b/libarchive/archive_write_format.3
index b3e7e35..e12e7d8 100644
--- a/libarchive/archive_write_format.3
+++ b/libarchive/archive_write_format.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd March 23, 2011
-.Dt archive_write_format 3
+.Dt ARCHIVE_WRITE_FORMAT 3
 .Os
 .Sh NAME
 .Nm archive_write_set_format_cpio ,
diff --git a/libarchive/archive_write_free.3 b/libarchive/archive_write_free.3
index d939780..27efe18 100644
--- a/libarchive/archive_write_free.3
+++ b/libarchive/archive_write_free.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd March 23, 2011
-.Dt archive_write_free 3
+.Dt ARCHIVE_WRITE_FREE 3
 .Os
 .Sh NAME
 .Nm archive_write_close ,
diff --git a/libarchive/archive_write_header.3 b/libarchive/archive_write_header.3
index f76175b..423b38e 100644
--- a/libarchive/archive_write_header.3
+++ b/libarchive/archive_write_header.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd March 23, 2011
-.Dt archive_write_header 3
+.Dt ARCHIVE_WRITE_HEADER 3
 .Os
 .Sh NAME
 .Nm archive_write_header
diff --git a/libarchive/archive_write_new.3 b/libarchive/archive_write_new.3
index 76515bb..d626ccb 100644
--- a/libarchive/archive_write_new.3
+++ b/libarchive/archive_write_new.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd March 23, 2011
-.Dt archive_write_new 3
+.Dt ARCHIVE_WRITE_NEW 3
 .Os
 .Sh NAME
 .Nm archive_write_new
diff --git a/libarchive/archive_write_open.3 b/libarchive/archive_write_open.3
index ab2d484..0d12cb3 100644
--- a/libarchive/archive_write_open.3
+++ b/libarchive/archive_write_open.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $
 .\"
 .Dd March 23, 2011
-.Dt archive_write 3
+.Dt ARCHIVE_WRITE 3
 .Os
 .Sh NAME
 .Nm archive_write_open ,
diff --git a/libarchive/archive_write_set_format_7zip.c b/libarchive/archive_write_set_format_7zip.c
index f405d1f..022b3a4 100644
--- a/libarchive/archive_write_set_format_7zip.c
+++ b/libarchive/archive_write_set_format_7zip.c
@@ -96,7 +96,7 @@ enum la_zaction {
 };
 
 /*
- * Universal zstream.
+ * A stream object of universal compressor.
  */
 struct la_zstream {
 	const uint8_t		*next_in;
@@ -154,8 +154,8 @@ struct file {
 #define HAS_STREAM	(1<<4)
 
 	struct {
-		time_t			 time;
-		long			 time_ns;
+		time_t		 time;
+		long		 time_ns;
 	}			 times[3];
 #define MTIME 0
 #define ATIME 1
@@ -455,6 +455,7 @@ _7z_write_header(struct archive_write *a, struct archive_entry *entry)
 	zip->total_number_entry++;
 	zip->total_bytes_entry_name += file->name_len + 2;
 	if (file->size == 0) {
+		/* Count up the number of empty files. */
 		zip->total_number_empty_entry++;
 		if (file->dir)
 			zip->total_number_dir_entry++;
@@ -488,6 +489,9 @@ _7z_write_header(struct archive_write *a, struct archive_entry *entry)
 	zip->entry_bytes_remaining = file->size;
 	zip->entry_crc32 = 0;
 
+	/*
+	 * Store a symbolic link name as file contents.
+	 */
 	if (archive_entry_filetype(entry) == AE_IFLNK) {
 		ssize_t bytes;
 		const void *p = (const void *)archive_entry_symlink(entry);
@@ -501,6 +505,9 @@ _7z_write_header(struct archive_write *a, struct archive_entry *entry)
 	return (r);
 }
 
+/*
+ * Write data to a temporary file.
+ */
 static int
 write_to_temp(struct archive_write *a, const void *buff, size_t s)
 {
@@ -719,19 +726,22 @@ _7z_close(struct archive_write *a)
 		zip->total_number_nonempty_entry =
 		    zip->total_number_entry - zip->total_number_empty_entry;
 
+		/* Connect an empty file list. */
 		*zip->file_list.last = zip->empty_list.first;
 		zip->file_list.last = zip->empty_list.last;
+		/* Connect a directory file list. */
 		ARCHIVE_RB_TREE_FOREACH(n, &(zip->rbtree)) {
 			file_register(zip, (struct file *)n);
 		}
 
 		/*
 		 * NOTE: 7z command supports just LZMA1, LZMA2 and COPY for
-		 * the header.
+		 * the compression type for encoding the header.
 		 */
 #if HAVE_LZMA_H
 		header_compression = _7Z_LZMA1;
-		/* If the stored file is only one, do not encode the header. */
+		/* If the stored file is only one, do not encode the header.
+		 * This is the same way 7z command does. */
 		if (zip->total_number_entry == 1)
 			header_compression = _7Z_COPY;
 #else
@@ -823,6 +833,9 @@ _7z_close(struct archive_write *a)
 	return (r);
 }
 
+/*
+ * Encode 64 bits value into 7-Zip's encoded UINT64 value.
+ */
 static int
 enc_uint64(struct archive_write *a, uint64_t val)
 {
@@ -1586,6 +1599,9 @@ compression_unsupported_encoder(struct archive *a,
 }
 #endif
 
+/*
+ * _7_COPY compressor.
+ */
 static int
 compression_init_encoder_copy(struct archive *a, struct la_zstream *lastrm)
 {
@@ -1631,6 +1647,9 @@ compression_end_copy(struct archive *a, struct la_zstream *lastrm)
 	return (ARCHIVE_OK);
 }
 
+/*
+ * _7_DEFLATE compressor.
+ */
 #ifdef HAVE_ZLIB_H
 static int
 compression_init_encoder_deflate(struct archive *a,
@@ -1741,6 +1760,9 @@ compression_init_encoder_deflate(struct archive *a,
 }
 #endif
 
+/*
+ * _7_BZIP2 compressor.
+ */
 #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 static int
 compression_init_encoder_bzip2(struct archive *a,
@@ -1860,6 +1882,9 @@ compression_init_encoder_bzip2(struct archive *a,
 }
 #endif
 
+/*
+ * _7_LZMA1, _7_LZMA2 compressor.
+ */
 #if defined(HAVE_LZMA_H)
 static int
 compression_init_encoder_lzma(struct archive *a,
@@ -2047,7 +2072,7 @@ compression_init_encoder_lzma2(struct archive *a,
 #endif
 
 /*
- * PPMd compression.
+ * _7_PPMD compressor.
  */
 static void *
 ppmd_alloc(void *p, size_t size)
@@ -2201,6 +2226,9 @@ compression_end_ppmd(struct archive *a, struct la_zstream *lastrm)
 	return (ARCHIVE_OK);
 }
 
+/*
+ * Universal compressor initializer.
+ */
 static int
 _7z_compression_init_encoder(struct archive_write *a, unsigned compression,
     int compression_level)
diff --git a/libarchive/archive_write_set_format_xar.c b/libarchive/archive_write_set_format_xar.c
index 4447f5a..bb9b551 100644
--- a/libarchive/archive_write_set_format_xar.c
+++ b/libarchive/archive_write_set_format_xar.c
@@ -684,21 +684,24 @@ xar_write_data(struct archive_write *a, const void *buff, size_t s)
 
 		archive_string_empty(&(xar->cur_file->script));
 		if (rsize > 2 && b[0] == '#' && b[1] == '!') {
-			char path[PATH_MAX];
 			size_t i, end, off;
 
-			end = sizeof(path);
-			if (end > rsize)
-				end = rsize;
 			off = 2;
 			if (b[off] == ' ')
 				off++;
+#ifdef PATH_MAX
+			if ((rsize - off) > PATH_MAX)
+				end = off + PATH_MAX;
+			else
+#endif
+				end = rsize;
+			/* Find the end of a script path. */
 			for (i = off; i < end && b[i] != '\0' &&
 			    b[i] != '\n' && b[i] != '\r' &&
 			    b[i] != ' ' && b[i] != '\t'; i++)
-				path[i - off] = b[i];
-			path[i - off] = '\0';
-			archive_strcpy(&(xar->cur_file->script), path);
+				;
+			archive_strncpy(&(xar->cur_file->script), b + off,
+			    i - off);
 		}
 	}
 #endif
diff --git a/libarchive/archive_write_set_format_zip.c b/libarchive/archive_write_set_format_zip.c
index 588c7f4..f07a14f 100644
--- a/libarchive/archive_write_set_format_zip.c
+++ b/libarchive/archive_write_set_format_zip.c
@@ -96,11 +96,13 @@ enum compression {
 #endif
 };
 
-static ssize_t archive_write_zip_data(struct archive_write *, const void *buff, size_t s);
+static ssize_t archive_write_zip_data(struct archive_write *,
+		   const void *buff, size_t s);
 static int archive_write_zip_close(struct archive_write *);
 static int archive_write_zip_free(struct archive_write *);
 static int archive_write_zip_finish_entry(struct archive_write *);
-static int archive_write_zip_header(struct archive_write *, struct archive_entry *);
+static int archive_write_zip_header(struct archive_write *,
+	      struct archive_entry *);
 static int archive_write_zip_options(struct archive_write *,
 	      const char *, const char *);
 static unsigned int dos_time(const time_t);
@@ -270,7 +272,8 @@ archive_write_set_format_zip(struct archive *_a)
 
 	zip = (struct zip *) calloc(1, sizeof(*zip));
 	if (zip == NULL) {
-		archive_set_error(&a->archive, ENOMEM, "Can't allocate zip data");
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate zip data");
 		return (ARCHIVE_FATAL);
 	}
 	zip->central_directory = NULL;
@@ -284,7 +287,8 @@ archive_write_set_format_zip(struct archive *_a)
 	zip->len_buf = 65536;
 	zip->buf = malloc(zip->len_buf);
 	if (zip->buf == NULL) {
-		archive_set_error(&a->archive, ENOMEM, "Can't allocate compression buffer");
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate compression buffer");
 		return (ARCHIVE_FATAL);
 	}
 #else
@@ -335,7 +339,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 
 	/* Entries other than a regular file or a folder are skipped. */
 	type = archive_entry_filetype(entry);
-	if ((type != AE_IFREG) & (type != AE_IFDIR)) {
+	if (type != AE_IFREG && type != AE_IFDIR && type != AE_IFLNK) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		    "Filetype not supported");
 		return ARCHIVE_FAILED;
@@ -410,8 +414,20 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 
 	/* Initialize the CRC variable and potentially the local crc32(). */
 	l->crc32 = crc32(0, NULL, 0);
-	l->compression = zip->compression;
-	l->compressed_size = 0;
+	if (type == AE_IFLNK) {
+		const char *p = archive_entry_symlink(l->entry);
+		if (p != NULL)
+			size = strlen(p);
+		else
+			size = 0;
+		zip->remaining_data_bytes = 0;
+		archive_entry_set_size(l->entry, size);
+		l->compression = COMPRESSION_STORE;
+		l->compressed_size = size;
+	} else {
+		l->compression = zip->compression;
+		l->compressed_size = 0;
+	}
 	l->next = NULL;
 	if (zip->central_directory == NULL) {
 		zip->central_directory = l;
@@ -420,22 +436,24 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 	}
 	zip->central_directory_end = l;
 
-	/* Store the offset of this header for later use in central directory. */
+	/* Store the offset of this header for later use in central
+	 * directory. */
 	l->offset = zip->written_bytes;
 
 	memset(&h, 0, sizeof(h));
 	archive_le32enc(&h.signature, ZIP_SIGNATURE_LOCAL_FILE_HEADER);
 	archive_le16enc(&h.version, ZIP_VERSION_EXTRACT);
 	archive_le16enc(&h.flags, l->flags);
-	archive_le16enc(&h.compression, zip->compression);
+	archive_le16enc(&h.compression, l->compression);
 	archive_le32enc(&h.timedate, dos_time(archive_entry_mtime(entry)));
 	archive_le16enc(&h.filename_length, (uint16_t)path_length(l->entry));
 
-	switch (zip->compression) {
+	switch (l->compression) {
 	case COMPRESSION_STORE:
-		/* Setting compressed and uncompressed sizes even when specification says
-		 * to set to zero when using data descriptors. Otherwise the end of the
-		 * data for an entry is rather difficult to find. */
+		/* Setting compressed and uncompressed sizes even when
+		 * specification says to set to zero when using data
+		 * descriptors. Otherwise the end of the data for an
+		 * entry is rather difficult to find. */
 		archive_le32enc(&h.compressed_size, size);
 		archive_le32enc(&h.uncompressed_size, size);
 		break;
@@ -448,8 +466,8 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 		zip->stream.opaque = Z_NULL;
 		zip->stream.next_out = zip->buf;
 		zip->stream.avail_out = zip->len_buf;
-		if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
-		    -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
+		if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION,
+		    Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't init deflate compressor");
 			return (ARCHIVE_FATAL);
@@ -495,6 +513,17 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 		return (ARCHIVE_FATAL);
 	zip->written_bytes += sizeof(e);
 
+	if (type == AE_IFLNK) {
+		const unsigned char *p;
+
+		p = (const unsigned char *)archive_entry_symlink(l->entry);
+		ret = __archive_write_output(a, p, size);
+		if (ret != ARCHIVE_OK)
+			return (ARCHIVE_FATAL);
+		zip->written_bytes += size;
+		l->crc32 = crc32(l->crc32, p, size);
+	}
+
 	if (ret2 != ARCHIVE_OK)
 		return (ret2);
 	return (ARCHIVE_OK);
@@ -512,7 +541,7 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
 
 	if (s == 0) return 0;
 
-	switch (zip->compression) {
+	switch (l->compression) {
 	case COMPRESSION_STORE:
 		ret = __archive_write_output(a, buff, s);
 		if (ret != ARCHIVE_OK) return (ret);
@@ -530,7 +559,8 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
 			if (ret == Z_STREAM_ERROR)
 				return (ARCHIVE_FATAL);
 			if (zip->stream.avail_out == 0) {
-				ret = __archive_write_output(a, zip->buf, zip->len_buf);
+				ret = __archive_write_output(a, zip->buf,
+					zip->len_buf);
 				if (ret != ARCHIVE_OK)
 					return (ret);
 				l->compressed_size += zip->len_buf;
@@ -564,7 +594,7 @@ archive_write_zip_finish_entry(struct archive_write *a)
 	size_t reminder;
 #endif
 
-	switch(zip->compression) {
+	switch(l->compression) {
 	case COMPRESSION_STORE:
 		break;
 #if HAVE_ZLIB_H
@@ -614,7 +644,8 @@ archive_write_zip_close(struct archive_write *a)
 	l = zip->central_directory;
 
 	/*
-	 * Formatting central directory file header fields that are fixed for all entries.
+	 * Formatting central directory file header fields that are
+	 * fixed for all entries.
 	 * Fields not used (and therefor 0) are:
 	 *
 	 *   - comment_length
@@ -634,18 +665,23 @@ archive_write_zip_close(struct archive_write *a)
 	while (l != NULL) {
 		archive_le16enc(&h.flags, l->flags);
 		archive_le16enc(&h.compression, l->compression);
-		archive_le32enc(&h.timedate, dos_time(archive_entry_mtime(l->entry)));
+		archive_le32enc(&h.timedate,
+			dos_time(archive_entry_mtime(l->entry)));
 		archive_le32enc(&h.crc32, l->crc32);
 		archive_le32enc(&h.compressed_size, l->compressed_size);
-		archive_le32enc(&h.uncompressed_size, archive_entry_size(l->entry));
-		archive_le16enc(&h.filename_length, (uint16_t)path_length(l->entry));
+		archive_le32enc(&h.uncompressed_size,
+			archive_entry_size(l->entry));
+		archive_le16enc(&h.filename_length,
+			(uint16_t)path_length(l->entry));
 		archive_le16enc(&h.extra_length, sizeof(e));
-		archive_le16enc(&h.attributes_external[2], archive_entry_mode(l->entry));
+		archive_le16enc(&h.attributes_external[2],
+			archive_entry_mode(l->entry));
 		archive_le32enc(&h.offset, l->offset);
 
 		/* Formatting extra data. */
 		archive_le16enc(&e.time_id, ZIP_SIGNATURE_EXTRA_TIMESTAMP);
-		archive_le16enc(&e.time_size, sizeof(e.mtime) + sizeof(e.time_flag));
+		archive_le16enc(&e.time_size,
+			sizeof(e.mtime) + sizeof(e.time_flag));
 		e.time_flag[0] = 0x07;
 		archive_le32enc(&e.mtime, archive_entry_mtime(l->entry));
 		archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_NEW_UNIX);
diff --git a/libarchive/archive_write_set_options.3 b/libarchive/archive_write_set_options.3
index 7e5cf21..9a8ea3d 100644
--- a/libarchive/archive_write_set_options.3
+++ b/libarchive/archive_write_set_options.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $
 .\"
 .Dd Feb 27, 2010
-.Dt archive_write_options 3
+.Dt ARCHIVE_WRITE_OPTIONS 3
 .Os
 .Sh NAME
 .Nm archive_write_set_filter_option ,
diff --git a/libarchive/cpio.5 b/libarchive/cpio.5
index f544628..13a4445 100644
--- a/libarchive/cpio.5
+++ b/libarchive/cpio.5
@@ -268,31 +268,6 @@ data, including ACLs and extended attributes, as special
 entries in cpio archives.
 .Pp
 XXX Others? XXX
-.Sh BUGS
-The
-.Dq CRC
-format is mis-named, as it uses a simple checksum and
-not a cyclic redundancy check.
-.Pp
-The old binary format is limited to 16 bits for user id,
-group id, device, and inode numbers.
-It is limited to 4 gigabyte file sizes.
-.Pp
-The old ASCII format is limited to 18 bits for
-the user id, group id, device, and inode numbers.
-It is limited to 8 gigabyte file sizes.
-.Pp
-The new ASCII format is limited to 4 gigabyte file sizes.
-.Pp
-None of the cpio formats store user or group names,
-which are essential when moving files between systems with
-dissimilar user or group numbering.
-.Pp
-Especially when writing older cpio variants, it may be necessary
-to map actual device/inode values to synthesized values that
-fit the available fields.
-With very large filesystems, this may be necessary even for
-the newer formats.
 .Sh SEE ALSO
 .Xr cpio 1 ,
 .Xr tar 5
@@ -323,3 +298,28 @@ license.
 The character format was adopted as part of
 .St -p1003.1-88 .
 XXX when did "newc" appear?  Who invented it?  When did HP come out with their variant?  When did Sun introduce ACLs and extended attributes? XXX
+.Sh BUGS
+The
+.Dq CRC
+format is mis-named, as it uses a simple checksum and
+not a cyclic redundancy check.
+.Pp
+The old binary format is limited to 16 bits for user id,
+group id, device, and inode numbers.
+It is limited to 4 gigabyte file sizes.
+.Pp
+The old ASCII format is limited to 18 bits for
+the user id, group id, device, and inode numbers.
+It is limited to 8 gigabyte file sizes.
+.Pp
+The new ASCII format is limited to 4 gigabyte file sizes.
+.Pp
+None of the cpio formats store user or group names,
+which are essential when moving files between systems with
+dissimilar user or group numbering.
+.Pp
+Especially when writing older cpio variants, it may be necessary
+to map actual device/inode values to synthesized values that
+fit the available fields.
+With very large filesystems, this may be necessary even for
+the newer formats.
diff --git a/libarchive/filter_fork_windows.c b/libarchive/filter_fork_windows.c
index 38b7097..272e56c 100644
--- a/libarchive/filter_fork_windows.c
+++ b/libarchive/filter_fork_windows.c
@@ -32,69 +32,73 @@
 pid_t
 __archive_create_child(const char *path, int *child_stdin, int *child_stdout)
 {
-	HANDLE childStdout[2], childStdin[2], childStdinWr, childStdoutRd;
+	HANDLE childStdout[2], childStdin[2],childStderr;
 	SECURITY_ATTRIBUTES secAtts;
 	STARTUPINFO staInfo;
 	PROCESS_INFORMATION childInfo;
 	char cmd[MAX_PATH];
-	DWORD mode;
 
 	secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
 	secAtts.bInheritHandle = TRUE;
 	secAtts.lpSecurityDescriptor = NULL;
 	if (CreatePipe(&childStdout[0], &childStdout[1], &secAtts, 0) == 0)
 		goto fail;
-	if (DuplicateHandle(GetCurrentProcess(), childStdout[0],
-	    GetCurrentProcess(), &childStdoutRd, 0, FALSE,
-	    DUPLICATE_SAME_ACCESS) == 0) {
+	if (!SetHandleInformation(childStdout[0], HANDLE_FLAG_INHERIT, 0))
+	{
 		CloseHandle(childStdout[0]);
 		CloseHandle(childStdout[1]);
 		goto fail;
 	}
-	CloseHandle(childStdout[0]);
-
 	if (CreatePipe(&childStdin[0], &childStdin[1], &secAtts, 0) == 0) {
-		CloseHandle(childStdoutRd);
+		CloseHandle(childStdout[0]);
 		CloseHandle(childStdout[1]);
 		goto fail;
 	}
-
-	if (DuplicateHandle(GetCurrentProcess(), childStdin[1],
-	    GetCurrentProcess(), &childStdinWr, 0, FALSE,
+	if (!SetHandleInformation(childStdin[1], HANDLE_FLAG_INHERIT, 0))
+	{
+		CloseHandle(childStdout[0]);
+		CloseHandle(childStdout[1]);
+		CloseHandle(childStdin[0]);
+		CloseHandle(childStdin[1]);
+		goto fail;
+	}
+	if (DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE),
+	    GetCurrentProcess(), &childStderr, 0, TRUE,
 	    DUPLICATE_SAME_ACCESS) == 0) {
-		CloseHandle(childStdoutRd);
+		CloseHandle(childStdout[0]);
 		CloseHandle(childStdout[1]);
 		CloseHandle(childStdin[0]);
 		CloseHandle(childStdin[1]);
 		goto fail;
 	}
-	CloseHandle(childStdin[1]);
 
 	memset(&staInfo, 0, sizeof(staInfo));
 	staInfo.cb = sizeof(staInfo);
+	staInfo.hStdError = childStderr;
 	staInfo.hStdOutput = childStdout[1];
 	staInfo.hStdInput = childStdin[0];
 	staInfo.wShowWindow = SW_HIDE;
-	staInfo.dwFlags = STARTF_USEFILLATTRIBUTE | STARTF_USECOUNTCHARS |
-	    STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+	staInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
 	strncpy(cmd, path, sizeof(cmd)-1);
 	cmd[sizeof(cmd)-1] = '\0';
 	if (CreateProcessA(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL,
 	    &staInfo, &childInfo) == 0) {
-		CloseHandle(childStdoutRd);
+		CloseHandle(childStdout[0]);
 		CloseHandle(childStdout[1]);
 		CloseHandle(childStdin[0]);
-		CloseHandle(childStdinWr);
+		CloseHandle(childStdin[1]);
+		CloseHandle(childStderr);
 		goto fail;
 	}
 	WaitForInputIdle(childInfo.hProcess, INFINITE);
 	CloseHandle(childInfo.hProcess);
 	CloseHandle(childInfo.hThread);
 
-	mode = PIPE_NOWAIT;
-	SetNamedPipeHandleState(childStdoutRd, &mode, NULL, NULL);
-	*child_stdout = _open_osfhandle((intptr_t)childStdoutRd, _O_RDONLY);
-	*child_stdin = _open_osfhandle((intptr_t)childStdinWr, _O_WRONLY);
+	*child_stdout = _open_osfhandle((intptr_t)childStdout[0], _O_RDONLY);
+	*child_stdin = _open_osfhandle((intptr_t)childStdin[1], _O_WRONLY);
+	
+	CloseHandle(childStdout[1]);
+	CloseHandle(childStdin[0]);
 
 	return (childInfo.dwProcessId);
 
diff --git a/libarchive/libarchive-formats.5 b/libarchive/libarchive-formats.5
index bd6bfe7..d223bf8 100644
--- a/libarchive/libarchive-formats.5
+++ b/libarchive/libarchive-formats.5
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/libarchive-formats.5 201077 2009-12-28 01:50:23Z kientzle $
 .\"
 .Dd December 27, 2009
-.Dt libarchive-formats 5
+.Dt LIBARCHIVE-FORMATS 5
 .Os
 .Sh NAME
 .Nm libarchive-formats
diff --git a/libarchive/libarchive_changes.3 b/libarchive/libarchive_changes.3
index 349eab9..6ee6af2 100644
--- a/libarchive/libarchive_changes.3
+++ b/libarchive/libarchive_changes.3
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd March 27, 2011
-.Dt libarchive_changes 3
+.Dt LIBARCHIVE_CHANGES 3
 .Os
 .Sh NAME
 .Nm changes in libarchive interface
diff --git a/libarchive/tar.5 b/libarchive/tar.5
index e55999b..65875bd 100644
--- a/libarchive/tar.5
+++ b/libarchive/tar.5
@@ -25,7 +25,7 @@
 .\" $FreeBSD: head/lib/libarchive/tar.5 201077 2009-12-28 01:50:23Z kientzle $
 .\"
 .Dd December 27, 2009
-.Dt tar 5
+.Dt TAR 5
 .Os
 .Sh NAME
 .Nm tar

-----------------------------------------------------------------------

Summary of changes:
 Utilities/cmlibarchive/.gitattributes              |    4 +-
 Utilities/cmlibarchive/CMakeLists.txt              |   11 +-
 Utilities/cmlibarchive/README-CMake.txt            |    8 +-
 Utilities/cmlibarchive/build/cmake/AddTest28.cmake |  107 --
 Utilities/cmlibarchive/build/version               |    2 +-
 Utilities/cmlibarchive/libarchive/archive.h        |   19 +-
 Utilities/cmlibarchive/libarchive/archive_entry.3  |    2 +-
 Utilities/cmlibarchive/libarchive/archive_entry.h  |    2 +-
 .../cmlibarchive/libarchive/archive_entry_acl.3    |    2 +-
 .../libarchive/archive_entry_linkify.3             |    2 +-
 .../cmlibarchive/libarchive/archive_entry_paths.3  |    2 +-
 .../cmlibarchive/libarchive/archive_entry_perms.3  |    2 +-
 .../cmlibarchive/libarchive/archive_entry_stat.3   |    2 +-
 .../cmlibarchive/libarchive/archive_entry_time.3   |    2 +-
 Utilities/cmlibarchive/libarchive/archive_read.3   |    2 +-
 Utilities/cmlibarchive/libarchive/archive_read.c   |   16 -
 .../cmlibarchive/libarchive/archive_read_data.3    |   16 +-
 .../libarchive/archive_read_data_into_fd.c         |    2 +-
 .../cmlibarchive/libarchive/archive_read_disk.3    |    4 +-
 .../cmlibarchive/libarchive/archive_read_extract.3 |    2 +-
 .../cmlibarchive/libarchive/archive_read_filter.3  |    2 +-
 .../cmlibarchive/libarchive/archive_read_format.3  |    2 +-
 .../cmlibarchive/libarchive/archive_read_free.3    |    2 +-
 .../cmlibarchive/libarchive/archive_read_header.3  |    2 +-
 .../cmlibarchive/libarchive/archive_read_new.3     |    2 +-
 .../cmlibarchive/libarchive/archive_read_open.3    |    2 +-
 .../libarchive/archive_read_set_options.3          |    2 +-
 .../libarchive/archive_read_support_format_7zip.c  | 1009 ++++++++++----------
 .../archive_read_support_format_iso9660.c          |    6 +-
 .../libarchive/archive_read_support_format_zip.c   |   35 +-
 Utilities/cmlibarchive/libarchive/archive_string.c |   51 +-
 Utilities/cmlibarchive/libarchive/archive_util.3   |    2 +-
 .../cmlibarchive/libarchive/archive_windows.c      |   42 +-
 .../cmlibarchive/libarchive/archive_windows.h      |    3 +-
 Utilities/cmlibarchive/libarchive/archive_write.3  |    2 +-
 .../libarchive/archive_write_blocksize.3           |    2 +-
 .../cmlibarchive/libarchive/archive_write_data.3   |    2 +-
 .../cmlibarchive/libarchive/archive_write_disk.3   |    2 +-
 .../libarchive/archive_write_disk_windows.c        |   28 +-
 .../cmlibarchive/libarchive/archive_write_filter.3 |    2 +-
 .../libarchive/archive_write_finish_entry.3        |    2 +-
 .../cmlibarchive/libarchive/archive_write_format.3 |    2 +-
 .../cmlibarchive/libarchive/archive_write_free.3   |    2 +-
 .../cmlibarchive/libarchive/archive_write_header.3 |    2 +-
 .../cmlibarchive/libarchive/archive_write_new.3    |    2 +-
 .../cmlibarchive/libarchive/archive_write_open.3   |    2 +-
 .../libarchive/archive_write_set_format_7zip.c     |   40 +-
 .../libarchive/archive_write_set_format_xar.c      |   17 +-
 .../libarchive/archive_write_set_format_zip.c      |   84 ++-
 .../libarchive/archive_write_set_options.3         |    2 +-
 Utilities/cmlibarchive/libarchive/cpio.5           |   50 +-
 .../cmlibarchive/libarchive/filter_fork_windows.c  |   46 +-
 .../cmlibarchive/libarchive/libarchive-formats.5   |    2 +-
 .../cmlibarchive/libarchive/libarchive_changes.3   |    2 +-
 Utilities/cmlibarchive/libarchive/tar.5            |    2 +-
 55 files changed, 819 insertions(+), 847 deletions(-)
 delete mode 100644 Utilities/cmlibarchive/build/cmake/AddTest28.cmake


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list